Omezení
Vzhledem k tomu, že aplikace v Androidu vyžadují generování typů proxy v Javě během procesu sestavení, není možné vygenerovat veškerý kód za běhu.
Jedná se o omezení Xamarin.Android v porovnání s desktopovým Mono:
Omezená podpora dynamického jazyka
Obálky s možností volání pro Android jsou potřeba pokaždé, když modul runtime Androidu potřebuje vyvolat spravovaný kód. Obálky s možností volání pro Android se generují v době kompilace na základě statické analýzy IL. Čistý výsledek tohoto: V žádném scénáři, ve kterém je vyžadováno podtřídy typů Javy (včetně nepřímé podtřídy), nemůžete použít dynamické jazyky (IronPython, IronRuby atd.), protože neexistuje způsob extrakce těchto dynamických typů v době kompilace, aby se vygenerovaly potřebné obálky s možností volání Pro Android.
Omezená podpora generování Javy
Aby kód Java mohl volat spravovaný kód, je potřeba vygenerovat obálky pro Android Callable Wrappers . Ve výchozím nastavení budou volatelné obálky androidu obsahovat (určité) deklarované konstruktory a metody, které přepíší virtuální metodu Java (tj. má RegisterAttribute
) nebo implementuje metodu rozhraní Java (rozhraní má Attribute
podobně).
Před vydáním verze 4.1 nelze deklarovat žádné další metody. Ve verzi Export
4.1 lze pomocí vlastních ExportField
atributů deklarovat metody a pole Jazyka Java v rámci obálky volatelné pro Android.
Chybějící konstruktory
Konstruktory zůstávají složité, pokud ExportAttribute
se nepoužívají. Algoritmus pro generování konstruktorů obálky s možností volání pro Android spočívá v tom, že konstruktor Jazyka Java se vygeneruje v následujících případech:
- Pro všechny typy parametrů existuje mapování Java.
- Základní třída deklaruje stejný konstruktor – To je povinné, protože obálka s možností volání pro Android musí vyvolat odpovídající konstruktor základní třídy; nelze použít žádné výchozí argumenty (protože neexistuje žádný snadný způsob, jak určit, jaké hodnoty se mají použít v Javě).
Představte si například následující třídu:
[Service]
class MyIntentService : IntentService {
public MyIntentService (): base ("value")
{
}
}
I když to vypadá dokonale logické, výsledný obálka pro Android volatelná v buildech release nebude obsahovat výchozí konstruktor. Pokud se tedy pokusíte spustit tuto službu (např. Context.StartService
se nezdaří:
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
Alternativním řešením je deklarovat výchozí konstruktor, doplnit ho ExportAttribute
pomocí a nastavit ExportAttribute.SuperStringArgument
:
[Service]
class MyIntentService : IntentService {
[Export (SuperArgumentsString = "\"value\"")]
public MyIntentService (): base("value")
{
}
// ...
}
Obecné třídy jazyka C#
Obecné třídy jazyka C# jsou podporovány pouze částečně. Jsou to následující omezení:
Obecné typy nesmí používat
[Export]
nebo[ExportField
]. Pokus o to vygenerujeXA4207
chybu.public abstract class Parcelable<T> : Java.Lang.Object, IParcelable { // Invalid; generates XA4207 [ExportField ("CREATOR")] public static IParcelableCreator CreateCreator () { ... }
Obecné metody nesmí používat
[Export]
nebo[ExportField]
:public class Example : Java.Lang.Object { // Invalid; generates XA4207 [Export] public static void Method<T>(T value) { ... } }
[ExportField]
nelze použít pro metody, které vracejívoid
:public class Example : Java.Lang.Object { // Invalid; generates XA4208 [ExportField ("CREATOR")] public static void CreateSomething () { } }
Instance obecných typů nesmí být vytvořeny z kódu Jazyka Java. Dají se bezpečně vytvářet jenom ze spravovaného kódu:
[Activity (Label="Die!", MainLauncher=true)] public class BadGenericActivity<T> : Activity { protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); } }
Částečná podpora obecných typů v Javě
Podpora vazeb obecných typů Java je omezená. Zejména členové obecné třídy instance, která je odvozena z jiné obecné (non-instanceiated) třídy jsou ponechány jako Java.Lang.Object. Například Metoda Android.Content.Intent.GetParcelableExtra vrátí Java.Lang.Object. Důvodem je vymazání obecných typů Javy. Máme některé třídy, které toto omezení nepoužívají, ale jsou ručně upraveny.