限制
由於 Android 上的應用程式需要在建置程式期間產生 Java Proxy 類型,因此無法在運行時間產生所有程式代碼。
相較於桌面Mono,以下是 Xamarin.Android 限制:
有限的動態語言支援
每當 Android 執行時間需要叫用 Managed 程式代碼時,都需要 Android 可呼叫包裝函 式。 Android 可呼叫包裝函式會根據 IL 的靜態分析,在編譯時期產生。 此結果的凈結果:您無法在任何需要 Java 類型子類別化(包括間接子類別化)的情況下使用動態語言 (IronPython、IronRuby 等),因為編譯時期無法擷取這些動態類型,以產生必要的 Android 可呼叫包裝函式。
有限的 Java 產生支援
必須產生 Android 可呼叫包裝函式 ,Java 程式代碼才能呼叫 Managed 程式代碼。 根據預設,Android 可呼叫包裝函式只會包含已宣告的建構函式和方法,這些建構函式會覆寫虛擬 Java 方法(亦即具有 RegisterAttribute
),或實作 Java 介面方法(介面同樣具有 Attribute
)。
在 4.1 版本之前,無法宣告其他方法。 在 4.1 版本中,Export
和 ExportField
自定義屬性可用來宣告 Android 可呼叫包裝函式內的 Java 方法和欄位。
遺漏建構函式
除非使用建構函式,否則 ExportAttribute
建構函式仍然棘手。 產生 Android 可呼叫包裝函式建構函式的演算法是,如果下列狀況,將會發出 Java 建構函式:
- 所有參數類型都有Java對應
- 基類會宣告相同的建構函式 – 這是必要的,因為Android可呼叫包裝函 式必須 叫用對應的基類建構函式;沒有預設自變數可以使用(因為無法輕易判斷Java內應該使用的值)。
例如,請參考下列類別:
[Service]
class MyIntentService : IntentService {
public MyIntentService (): base ("value")
{
}
}
雖然這看起來完全合乎邏輯,但發行組建中產生的 Android 可呼叫包裝函式將不會包含預設建構函式。 因此,如果您嘗試啟動此服務(例如 Context.StartService
,它會失敗:
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
因應措施是宣告預設建構函式、使用 ExportAttribute
裝飾它,並設定 ExportAttribute.SuperStringArgument
:
[Service]
class MyIntentService : IntentService {
[Export (SuperArgumentsString = "\"value\"")]
public MyIntentService (): base("value")
{
}
// ...
}
泛型 C# 類別
僅部分支援泛型 C# 類別。 存在下列限制:
泛型型別不得使用
[Export]
或[ExportField
。 嘗試這樣做會產生XA4207
錯誤。public abstract class Parcelable<T> : Java.Lang.Object, IParcelable { // Invalid; generates XA4207 [ExportField ("CREATOR")] public static IParcelableCreator CreateCreator () { ... }
泛型方法不得使用
[Export]
或[ExportField]
:public class Example : Java.Lang.Object { // Invalid; generates XA4207 [Export] public static void Method<T>(T value) { ... } }
[ExportField]
無法在傳回void
的方法上使用 :public class Example : Java.Lang.Object { // Invalid; generates XA4208 [ExportField ("CREATOR")] public static void CreateSomething () { } }
泛型型 別的實例不得 從Java程式碼建立。 它們只能安全地從Managed程式代碼建立:
[Activity (Label="Die!", MainLauncher=true)] public class BadGenericActivity<T> : Activity { protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); } }
部分 Java 泛型支援
Java 泛型系結支援有限。 特別是,衍生自另一個泛型(非具現化)類別之泛型實例類別的成員會公開為 Java.Lang.Object。 例如, Android.Content.Intent.GetParcelableExtra 方法會傳回 Java.Lang.Object。 這是因為清除的Java泛型。 我們有一些類別不適用此限制,但會手動調整。