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 Attributeebenfalls ).

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:

  1. Es gibt eine Java-Zuordnung für alle Parametertypen
  2. 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.StartServiceschlä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 ExportAttributezu 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 [ExportFieldverwenden[Export]. Der Versuch, dies zu tun, führt zu einem XA4207 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ückgeben void:

    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.