限制

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

以下是与桌面 Mono 相比的 Xamarin.Android 限制:

有限动态语言支持

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

有限的 Java 生成支持

需要生成 Android 可调用包装器,以便 Java 代码调用托管代码。 默认情况下,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 泛型擦除造成的。 我们有些类不适用此限制,但它们是手动调整的。