Bagikan melalui


Batasan

Karena aplikasi di Android memerlukan pembuatan jenis proksi Java selama proses build, tidak dimungkinkan untuk menghasilkan semua kode saat runtime.

Ini adalah batasan Xamarin.Android dibandingkan dengan Mono desktop:

Dukungan Bahasa Dinamis Terbatas

Pembungkus yang dapat dipanggil Android diperlukan kapan saja runtime Android perlu memanggil kode terkelola. Pembungkus yang dapat dipanggil Android dihasilkan pada waktu kompilasi, berdasarkan analisis statis IL. Hasil bersih dari ini: Anda tidak dapat menggunakan bahasa dinamis (IronPython, IronRuby, dll.) dalam skenario apa pun di mana subkelas jenis Java diperlukan (termasuk subkelas tidak langsung), karena tidak ada cara untuk mengekstrak jenis dinamis ini pada waktu kompilasi untuk menghasilkan pembungkus panggilan Android yang diperlukan.

Dukungan Generasi Java Terbatas

Pembungkus Yang Dapat Dipanggil Android perlu dibuat agar kode Java dapat memanggil kode terkelola. Secara default, pembungkus yang dapat dipanggil Android hanya akan berisi (tertentu) konstruktor dan metode yang dideklarasikan yang mengambil alih metode Java virtual (yaitu memiliki RegisterAttribute) atau menerapkan metode antarmuka Java (antarmuka juga memiliki Attribute).

Sebelum rilis 4.1, tidak ada metode tambahan yang dapat dideklarasikan. Dengan rilis 4.1, Export atribut kustom dan ExportField dapat digunakan untuk mendeklarasikan metode dan bidang Java dalam Android Callable Wrapper.

Konstruktor yang hilang

Konstruktor tetap sulit, kecuali ExportAttribute digunakan. Algoritma untuk menghasilkan konstruktor pembungkus yang dapat dipanggil Android adalah bahwa konstruktor Java akan dipancarkan jika:

  1. Ada pemetaan Java untuk semua jenis parameter
  2. Kelas dasar mendeklarasikan konstruktor yang sama - Ini diperlukan karena pembungkus yang dapat dipanggil Android harus memanggil konstruktor kelas dasar yang sesuai; tidak ada argumen default yang dapat digunakan (karena tidak ada cara mudah untuk menentukan nilai apa yang harus digunakan dalam Java).

Sebagai contoh, perhatikan kelas berikut:

[Service]
class MyIntentService : IntentService {
    public MyIntentService (): base ("value")
    {
    }
}

Meskipun ini terlihat sangat logis, pembungkus yang dapat dipanggil Android yang dihasilkan dalam build Rilis tidak akan berisi konstruktor default. Akibatnya, jika Anda mencoba memulai layanan ini (misalnya Context.StartService, itu akan gagal:

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

Solusinya adalah mendeklarasikan konstruktor default, menghiasinya dengan ExportAttribute, dan mengatur ExportAttribute.SuperStringArgument:

[Service]
class MyIntentService : IntentService {
    [Export (SuperArgumentsString = "\"value\"")]
    public MyIntentService (): base("value")
    {
    }

    // ...
}

Kelas C# generik

Kelas C# generik hanya didukung sebagian. Keterbatasan berikut ada:

  • Tipe generik mungkin tidak menggunakan [Export] atau [ExportField]. Mencoba melakukannya akan menghasilkan kesalahan XA4207 .

    public abstract class Parcelable<T> : Java.Lang.Object, IParcelable
    {
        // Invalid; generates XA4207
        [ExportField ("CREATOR")]
        public static IParcelableCreator CreateCreator ()
        {
            ...
    }
    
  • Metode generik tidak boleh menggunakan [Export] atau [ExportField]:

    public class Example : Java.Lang.Object
    {
    
        // Invalid; generates XA4207
        [Export]
        public static void Method<T>(T value)
        {
            ...
        }
    }
    
  • [ExportField] tidak dapat digunakan pada metode yang mengembalikan void:

    public class Example : Java.Lang.Object
    {
        // Invalid; generates XA4208
        [ExportField ("CREATOR")]
        public static void CreateSomething ()
        {
        }
    }
    
  • Instans jenis Generik tidak boleh dibuat dari kode Java. Mereka hanya dapat dibuat dengan aman dari kode terkelola:

    [Activity (Label="Die!", MainLauncher=true)]
    public class BadGenericActivity<T> : Activity
    {
        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);
        }
    }
    

Dukungan Generik Java Parsial

Dukungan pengikatan generik Java terbatas. Terutama, anggota dalam kelas instans generik yang berasal dari kelas generik lain (non-instans) dibiarkan terekspos sebagai Java.Lang.Object. Misalnya, metode Android.Content.Intent.GetParcelableExtra mengembalikan Java.Lang.Object. Hal ini disebabkan oleh generik Java yang dihapus. Kami memiliki beberapa kelas yang tidak menerapkan batasan ini, tetapi mereka disesuaikan secara manual.