Einschränkungen
Da Anwendungen unter Android das Generieren von Java-Proxytypen während des Buildvorgangs erfordern, ist es nicht möglich, den gesamten Code zur Laufzeit zu generieren.
Dies sind die Xamarin.Android-Einschränkungen im Vergleich zu Desktop Mono:
Unterstützung für eingeschränkte dynamische Sprache
Aufrufbare Wrapper für Android sind immer erforderlich, wenn die Android-Runtime verwalteten Code aufrufen muss. Android-aufrufbare Wrapper werden zur Kompilierzeit generiert, basierend auf der statischen Analyse von IL. Das Nettoergebnis: Sie können keine dynamischen Sprachen (IronPython, IronRuby usw.) in jedem Szenario verwenden, in dem eine Unterklasse von Java-Typen erforderlich ist (einschließlich indirekter Unterklassen), da es keine Möglichkeit gibt, diese dynamischen Typen zur Kompilierzeit zu extrahieren, um die erforderlichen aufrufbaren Android-Wrapper zu generieren.
Eingeschränkte Unterstützung der Java-Generierung
Android Callable Wrapper müssen generiert werden, damit Java-Code verwalteten Code aufrufen kann. Standardmäßig enthalten aufrufbare Android-Wrapper nur (bestimmte) deklarierte Konstruktoren und Methoden, die eine virtuelle Java-Methode überschreiben (d. h. sie hat RegisterAttribute
) oder eine Java-Schnittstellenmethode implementieren (die Schnittstelle hat Attribute
ebenfalls ).
Vor version 4.1 konnten keine zusätzlichen Methoden deklariert werden. Ab Version 4.1 können die Export
benutzerdefinierten Attribute und ExportField
zum Deklarieren von Java-Methoden und -Feldern im Android Callable Wrapper verwendet werden.
Fehlende Konstruktoren
Konstruktoren bleiben schwierig, es sei denn ExportAttribute
, sie werden verwendet. Der Algorithmus zum Generieren von android-aufrufbaren Wrapperkonstruktoren ist, dass ein Java-Konstruktor ausgegeben wird, wenn:
- Es gibt eine Java-Zuordnung für alle Parametertypen
- Die Basisklasse deklariert denselben Konstruktor– Dies ist erforderlich, da der aufrufbare Android-Wrapper den entsprechenden Basisklassenkonstruktor aufrufen muss . Es können keine Standardargumente verwendet werden (da es keine einfache Möglichkeit gibt, zu bestimmen, welche Werte in Java verwendet werden sollen).
Betrachten Sie beispielsweise die folgende Klasse:
[Service]
class MyIntentService : IntentService {
public MyIntentService (): base ("value")
{
}
}
Dies sieht zwar vollkommen logisch aus, aber der resultierende aufrufbare Android-Wrapper in Releasebuilds enthält keinen Standardkonstruktor. Wenn Sie also versuchen, diesen Dienst zu starten (z. B. Context.StartService
schlägt dies fehl:
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
Die Problemumgehung besteht darin, einen Standardkonstruktor zu deklarieren, ihn mit dem ExportAttribute
zu versehen und festzulegen ExportAttribute.SuperStringArgument
:
[Service]
class MyIntentService : IntentService {
[Export (SuperArgumentsString = "\"value\"")]
public MyIntentService (): base("value")
{
}
// ...
}
Generische C#-Klassen
Generische C#-Klassen werden nur teilweise unterstützt. Es gelten die folgenden Einschränkungen:
Generische Typen dürfen nicht oder
[ExportField
verwenden[Export]
. Der Versuch, dies zu tun, führt zu einemXA4207
Fehler.public abstract class Parcelable<T> : Java.Lang.Object, IParcelable { // Invalid; generates XA4207 [ExportField ("CREATOR")] public static IParcelableCreator CreateCreator () { ... }
Generische Methoden dürfen nicht oder
[ExportField]
verwenden[Export]
:public class Example : Java.Lang.Object { // Invalid; generates XA4207 [Export] public static void Method<T>(T value) { ... } }
[ExportField]
darf nicht für Methoden verwendet werden, die folgendes zurückgebenvoid
:public class Example : Java.Lang.Object { // Invalid; generates XA4208 [ExportField ("CREATOR")] public static void CreateSomething () { } }
Instanzen generischer Typen dürfen nicht aus Java-Code erstellt werden. Sie können nur sicher aus verwaltetem Code erstellt werden:
[Activity (Label="Die!", MainLauncher=true)] public class BadGenericActivity<T> : Activity { protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); } }
Teilweise Java Generics-Unterstützung
Die Java Generics-Bindungsunterstützung ist begrenzt. Insbesondere werden Member in einer generischen instance-Klasse, die von einer anderen generischen (nicht instanziierten) Klasse abgeleitet ist, als Java.Lang.Object verfügbar gemacht. Die Android.Content.Intent.GetParcelableExtra-Methode gibt beispielsweise Java.Lang.Object zurück. Dies ist auf gelöschte Java-Generika zurückzuführen. Es gibt einige Klassen, die diese Einschränkung nicht anwenden, aber sie werden manuell angepasst.