Ograniczenia
Ponieważ aplikacje w systemie Android wymagają generowania typów serwerów proxy Java podczas procesu kompilacji, nie można wygenerować całego kodu w czasie wykonywania.
Są to ograniczenia platformy Xamarin.Android w porównaniu z wersją Desktop Mono:
Ograniczona obsługa języka dynamicznego
Wywoływane otoki systemu Android są potrzebne w dowolnym momencie, gdy środowisko uruchomieniowe systemu Android musi wywołać kod zarządzany. Otoki z możliwością wywołania systemu Android są generowane w czasie kompilacji na podstawie statycznej analizy il. Wynik netto tego: nie można używać języków dynamicznych (IronPython, IronRuby itp.) w każdym scenariuszu, w którym wymagane jest podklasowanie typów Języka Java (w tym pośrednie podklasy), ponieważ nie ma możliwości wyodrębniania tych typów dynamicznych w czasie kompilacji w celu wygenerowania niezbędnych otoek z możliwością wywołania systemu Android.
Ograniczona obsługa generacji języka Java
W celu wywołania kodu zarządzanego w języku Java należy wygenerować zawinięcia z możliwością wywoływania kodu z możliwością wywołania kodu zarządzanego w systemie Android. Domyślnie wywoływane otoki systemu Android będą zawierać tylko (niektóre) zadeklarowane konstruktory i metody, które zastępują wirtualną metodę Java (tj. ma RegisterAttribute
) lub implementują metodę interfejsu Java (interfejs podobnie ma Attribute
).
Przed wydaniem wersji 4.1 nie można zadeklarować żadnych dodatkowych metod. W wersji Export
4.1 atrybuty niestandardowe i ExportField
mogą służyć do deklarowania metod i pól Języka Java w zawijaniu wywoływanej przez system Android.
Brakujące konstruktory
Konstruktory pozostają trudne, chyba że ExportAttribute
jest używany. Algorytm generowania konstruktorów otoki z możliwością wywołania systemu Android polega na tym, że konstruktor Języka Java będzie emitowany w następujących przypadkach:
- Istnieje mapowanie języka Java dla wszystkich typów parametrów
- Klasa bazowa deklaruje ten sam konstruktor — jest to wymagane, ponieważ otoka wywoływana przez system Android musi wywołać odpowiedni konstruktor klasy bazowej. Nie można użyć żadnych argumentów domyślnych (ponieważ nie ma łatwego sposobu określania wartości, które mają być używane w języku Java).
Rozważmy na przykład następującą klasę:
[Service]
class MyIntentService : IntentService {
public MyIntentService (): base ("value")
{
}
}
Chociaż wygląda to doskonale logicznie, wynikowa otoka wywoływana przez system Android w kompilacjach wydania nie będzie zawierać domyślnego konstruktora. W związku z tym próba uruchomienia tej usługi (np. Context.StartService
, zakończy się niepowodzeniem:
E/AndroidRuntime(31766): FATAL EXCEPTION: main
E/AndroidRuntime(31766): java.lang.RuntimeException: Unable to instantiate service example.MyIntentService: java.lang.InstantiationException: can't instantiate class example.MyIntentService; no empty constructor
E/AndroidRuntime(31766): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2347)
E/AndroidRuntime(31766): at android.app.ActivityThread.access$1600(ActivityThread.java:130)
E/AndroidRuntime(31766): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1277)
E/AndroidRuntime(31766): at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(31766): at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(31766): at android.app.ActivityThread.main(ActivityThread.java:4745)
E/AndroidRuntime(31766): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(31766): at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(31766): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
E/AndroidRuntime(31766): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
E/AndroidRuntime(31766): at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(31766): Caused by: java.lang.InstantiationException: can't instantiate class example.MyIntentService; no empty constructor
E/AndroidRuntime(31766): at java.lang.Class.newInstanceImpl(Native Method)
E/AndroidRuntime(31766): at java.lang.Class.newInstance(Class.java:1319)
E/AndroidRuntime(31766): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2344)
E/AndroidRuntime(31766): ... 10 more
Obejście polega na zadeklarowaniu domyślnego konstruktora, ozdobieniu go elementem ExportAttribute
i ustawieniu elementu ExportAttribute.SuperStringArgument
:
[Service]
class MyIntentService : IntentService {
[Export (SuperArgumentsString = "\"value\"")]
public MyIntentService (): base("value")
{
}
// ...
}
Ogólne klasy języka C#
Ogólne klasy języka C# są obsługiwane tylko częściowo. Istnieją następujące ograniczenia:
Typy ogólne mogą nie być używane
[Export]
lub[ExportField
]. Próba wykonania tej czynności spowoduje wygenerowanie błęduXA4207
.public abstract class Parcelable<T> : Java.Lang.Object, IParcelable { // Invalid; generates XA4207 [ExportField ("CREATOR")] public static IParcelableCreator CreateCreator () { ... }
Metody ogólne mogą nie być używane
[Export]
lub[ExportField]
:public class Example : Java.Lang.Object { // Invalid; generates XA4207 [Export] public static void Method<T>(T value) { ... } }
[ExportField]
nie może być używany w metodach, które zwracają wartośćvoid
:public class Example : Java.Lang.Object { // Invalid; generates XA4208 [ExportField ("CREATOR")] public static void CreateSomething () { } }
Wystąpienia typów ogólnych nie mogą być tworzone na podstawie kodu Java. Można je bezpiecznie tworzyć tylko na podstawie kodu zarządzanego:
[Activity (Label="Die!", MainLauncher=true)] public class BadGenericActivity<T> : Activity { protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); } }
Obsługa częściowych typów ogólnych Języka Java
Obsługa powiązań ogólnych języka Java jest ograniczona. Szczególnie elementy członkowskie w klasie wystąpienia ogólnego pochodzącej z innej klasy ogólnej (nieopartej wystąpieniem) są widoczne jako Java.Lang.Object. Na przykład metoda Android.Content.Intent.GetParcelableExtra zwraca metodę Java.Lang.Object. Wynika to z wymazanych typów ogólnych języka Java. Mamy kilka klas, które nie stosują tego ograniczenia, ale są one ręcznie dostosowywane.