Поделиться через


Ограничения

Так как приложения в Android требуют создания типов прокси-серверов Java во время сборки, невозможно создать весь код во время выполнения.

Это ограничения Xamarin.Android по сравнению с классическим Mono:

Ограниченная поддержка динамического языка

Вызываемые оболочки Android необходимы в любой момент, когда среде выполнения Android необходимо вызвать управляемый код. Вызываемые оболочки Android создаются во время компиляции на основе статического анализа IL. Чистый результат этого: нельзя использовать динамические языки (IronPython, IronRuby и т. д.), в любом сценарии, где требуется подкласс типов Java (включая косвенное подклассирование), так как во время компиляции невозможно извлечь эти динамические типы во время компиляции, чтобы создать необходимые вызываемые оболочки Android.

Ограниченная поддержка создания Java

Вызываемые оболочки Android необходимо создать, чтобы код Java вызывал управляемый код. По умолчанию вызываемые оболочки Android будут содержать только объявленные конструкторы и методы, которые переопределяют виртуальный метод Java (т. е. он имеетRegisterAttribute) или реализует метод интерфейса Java (интерфейс аналогично).Attribute

До выпуска 4.1 дополнительные методы не могут быть объявлены. В выпуске ExportExportField 4.1 можно использовать настраиваемые атрибуты для объявления методов и полей Java в вызываемой оболочке Android.

Отсутствующие конструкторы

Конструкторы остаются сложными, если 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

Обходной путь — объявление конструктора по умолчанию, его украшение ExportAttributeExportAttribute.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. У нас есть некоторые классы, которые не применяют это ограничение, но они корректируются вручную.