限制

由于 Android 上的应用程序在生成过程中需要生成 Java 代理类型,因此无法在运行时生成所有代码。

与桌面 Mono 相比,Xamarin.iOS 存在以下限制:

有限的动态语言支持

Android 运行时每次需要调用托管代码时都需要 Android 可调用包装器。 Android 可调用包装器是在编译时基于 IL 的静态分析生成的。 最终结果是:在需要进行 Java 类型子类化(包括间接子类化)的任何场景中,你都无法使用动态语言(IronPython、IronRuby,等等),因为在编译时无法提取这些动态类型来生成所需的 Android 可调用包装器。

有限的 Java 生成支持

要想让 Java 代码调用托管代码,需要生成 Android 可调用包装器。 默认情况下,Android 可调用包装器将仅包含(某些)已声明的构造函数和方法,这些构造函数和方法替代虚拟 Java 方法(即它具有 RegisterAttribute)或实现 Java 接口方法(接口同样具有 Attribute)。

在 4.1 版本之前,无法声明其他方法。 在 4.1 版本中,可以使用 ExportExportField 自定义属性来声明 Android 可调用包装器中的 Java 方法和字段

缺少构造函数

构造函数仍然很棘手,除非使用 ExportAttribute。 用于生成 Android 可调用包装器构造函数的算法是在以下情况下发出 Java 构造函数:

  1. 所有参数类型都有一个 Java 映射
  2. 基类声明相同的构造函数 - 这是必需的,因为 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 代码创建泛型类型的实例。 只能从托管代码安全地创建它们:

    [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 泛型。 我们有一些不存在此限制的类,但它们是手动调整的。