限制
由于 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 版本中,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 代码创建泛型类型的实例。 只能从托管代码安全地创建它们:
[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 泛型擦除造成的。 我们有些类不适用此限制,但它们是手动调整的。