Mimari

Xamarin.Android uygulamaları Mono yürütme ortamında çalışır. Bu yürütme ortamı, Android Çalışma Zamanı (ART) sanal makinesiyle yan yana çalışır. Her iki çalışma zamanı ortamı da Linux çekirdeğinin üzerinde çalışır ve geliştiricilerin temel sisteme erişmesini sağlayan kullanıcı koduna çeşitli API'leri kullanıma sunar. Mono çalışma zamanı C dilinde yazılır.

Temel linux işletim sistemi olanaklarına erişmek için Sistem, System.IO, System.Net ve diğer .NET sınıf kitaplıklarını kullanabilirsiniz.

Android'de Ses, Grafik, OpenGL ve Telefon gibi sistem olanaklarının çoğu yerel uygulamalar tarafından doğrudan kullanılamaz, yalnızca Java.* ad alanlarının birinde veya Android.* ad alanında bulunan Android Çalışma Zamanı Java API'leri aracılığıyla kullanıma sunulur. Mimari kabaca şöyledir:

Çekirdeğin üzerinde ve .NET/Java + bağlamalarının altındaki Mono ve ART diyagramı

Xamarin.Android geliştiricileri, bildikleri .NET API'lerine (düşük düzey erişim için) arayarak veya Android Çalışma Zamanı tarafından kullanıma sunulan Java API'lerine köprü sağlayan Android ad alanında kullanıma sunulan sınıfları kullanarak işletim sistemindeki çeşitli özelliklere erişiyor.

Android sınıflarının Android Çalışma Zamanı sınıfları ile iletişim kurması hakkında daha fazla bilgi için API Tasarımı belgesine bakın.

Uygulama Paketleri

Android uygulama paketleri, .apk dosya uzantısına sahip ZIP kapsayıcılarıdır. Xamarin.Android uygulama paketleri, aşağıdaki eklemelerle normal Android paketleriyle aynı yapıya ve düzene sahiptir:

  • Uygulama derlemeleri (IL içeren) derlemeler klasöründe sıkıştırılmamış olarak depolanır. Release derlemelerinde işlem başlatma sırasında .apk işleme mmap() eklenir ve derlemeler bellekten yüklenir. Derlemelerin yürütülmeden önce ayıklanması gerekmediğinden bu işlem daha hızlı uygulama başlatmaya izin verir.

  • Not: Assembly.Location ve Assembly.CodeBase gibi derleme konumu bilgileri Sürüm derlemelerinde kullanılamaz. Bunlar ayrı dosya sistemi girdileri olarak mevcut değildir ve kullanılabilir konumları yoktur.

  • Mono çalışma zamanını içeren yerel kitaplıklar .apk içinde bulunur. Xamarin.Android uygulaması, istenen/hedeflenen Android mimarileri için yerel kitaplıklar içermelidir; örneğin armeabi , armeabi-v7a , x86 . Xamarin.Android uygulamaları, uygun çalışma zamanı kitaplıklarını içermediği sürece bir platformda çalıştırılamaz.

Xamarin.Android uygulamaları, Android'in yönetilen koda çağrılmasına izin vermek için Android Çağrılabilen Sarmalayıcılar da içerir.

Android Çağrılabilir Sarmalayıcıları

  • Android çağrılabilir sarmalayıcılar , Android çalışma zamanının yönetilen kodu çağırması gerektiğinde kullanılan bir JNI köprüsü. Android çağrılabilen sarmalayıcılar, sanal yöntemlerin nasıl geçersiz kılınabileceği ve Java arabirimlerinin nasıl uygulanabileceğidir. Daha fazla bilgi için Java Tümleştirmesine Genel Bakış belgesine bakın.

Yönetilen Çağrılabilen Sarmalayıcılar

Yönetilen çağrılabilir sarmalayıcılar, yönetilen kodun Android kodunu çağırması ve sanal yöntemleri geçersiz kılma ve Java arabirimlerini uygulama desteği sağlaması için her zaman kullanılan bir JNI köprüsü. Android.* ve ilgili ad alanlarının tamamı, .jar bağlaması aracılığıyla oluşturulan çağrılabilen sarmalayıcılardır. Yönetilen çağrılabilen sarmalayıcılar, yönetilen ve Android türleri arasında dönüştürme ve JNI aracılığıyla temel alınan Android platformu yöntemlerini çağırmaktan sorumludur.

Oluşturulan her yönetilen çağrılabilen sarmalayıcı, Android.Runtime.IJavaObject.Handle özelliği aracılığıyla erişilebilen bir Java genel başvurusu içerir. Genel başvurular, Java örnekleriyle yönetilen örnekler arasında eşleme sağlamak için kullanılır. Genel başvurular sınırlı bir kaynaktır: öykünücüler aynı anda yalnızca 2000 genel başvuru olmasına izin verirken, çoğu donanım aynı anda 52.000'den fazla genel başvuru bulunmasına izin verir.

Genel başvuruların ne zaman oluşturulup yok edildiğini izlemek için, debug.mono.log sistem özelliğini gref içerecek şekilde ayarlayabilirsiniz.

Genel başvurular, yönetilen çağrılabilen sarmalayıcıda Java.Lang.Object.Dispose() çağrılarak açıkça serbest bırakılabilir. Bu işlem Java örneği ile yönetilen örnek arasındaki eşlemeyi kaldırır ve Java örneğinin toplanmasına izin verir. Java örneğine yönetilen koddan yeniden erişilirse, bunun için yeni bir yönetilen çağrılabilen sarmalayıcı oluşturulur.

Örnek yanlışlıkla iş parçacıkları arasında paylaşılabiliyorsa Yönetilen Çağrılabilen Sarmalayıcılar yok edilirken dikkatli olunmalıdır, örneğin kullanımdan kaldırılması diğer iş parçacıklarından gelen başvuruları etkiler. Maksimum güvenlik için, yalnızca Dispose() her zaman yeni örnekler ayırdığını bildiğiniz yöntemlerle new veya yöntemlerden ayrılmış örneklerin, önbelleğe alınmış örnekleri ayırmaması, iş parçacıkları arasında yanlışlıkla örnek paylaşımına neden olabilir.

Yönetilen Çağrılabilen Sarmalayıcı Alt Sınıfları

Yönetilen çağrılabilir sarmalayıcı alt sınıfları, uygulamaya özgü tüm "ilginç" mantığın yaşayabileceği yerdir. Bunlar özel Android.App.Activity alt sınıflarını (varsayılan proje şablonundaki Activity1 türü gibi) içerir. (Özellikle, bunlar herhangi bir RegisterAttribute özel özniteliği veya RegisterAttribute.DoNotGenerateAcw içermeyen Java.Lang.Object alt sınıfları false değeridir ve bu varsayılan değerdir.)

Yönetilen çağrılabilen sarmalayıcılar gibi, yönetilen çağrılabilen sarmalayıcı alt sınıfları da Java.Lang.Object.Handle özelliği aracılığıyla erişilebilen genel bir başvuru içerir. Yönetilen çağrılabilen sarmalayıcılarda olduğu gibi genel başvurular da Java.Lang.Object.Dispose() çağrılarak açıkça serbest bırakılabilir. Yönetilen çağrılabilen sarmalayıcılardan farklı olarak, örneğin Dispose()-ing komutu Java örneği (Android Çağrılabilen Sarmalayıcı örneği) ile yönetilen örnek arasındaki eşlemeyi bozacağı için, bu tür örneklerin yok edilmesine dikkat edilmelidir.

Java Etkinleştirme

Java'dan bir Android Çağrılabilir Sarmalayıcı (ACW) oluşturulduğunda, ACW oluşturucu ilgili C# oluşturucusunun çağrılmasına neden olur. Örneğin, MainActivity için ACW, MainActivity'nin varsayılan oluşturucusunu çağıran bir varsayılan oluşturucu içerir. (Bu işlem, ACW oluşturucuları içinde TypeManager.Activate() çağrısı.)

Sonuç olarak başka bir oluşturucu imzası daha vardır: (IntPtr, JniHandleOwnership) oluşturucu. Bir Java nesnesi yönetilen koda sunulduğunda (IntPtr, JniHandleOwnership) oluşturucu çağrılır ve JNI tanıtıcısını yönetmek için Yönetilen Çağrılabilir Sarmalayıcı oluşturulmalıdır. Bu genellikle otomatik olarak yapılır.

(IntPtr, JniHandleOwnership) oluşturucusunun Yönetilen Çağrılabilen Sarmalayıcı alt sınıfında el ile sağlanması gereken iki senaryo vardır:

  1. Android.App.Application alt sınıfına eklenmiştir. Uygulama özeldir; varsayılan Applicaton oluşturucu hiçbir zaman çağrılamaz ve bunun yerine (IntPtr, JniHandleOwnership) oluşturucu sağlanmalıdır.

  2. Bir temel sınıf oluşturucusundan sanal yöntem çağırma.

(2) sızdıran bir soyutlamadır. C# dilinde olduğu gibi Java'da da bir oluşturucudan sanal yöntemlere çağrılar her zaman en çok türetilmiş yöntem uygulamasını çağırır. Örneğin, TextView(Context, AttributeSet, int) oluşturucu, TextView.DefaultMovementMethod özelliği olarak bağlanan TextView.getDefaultMovementMethod() sanal yöntemini çağırır. Bu nedenle, bir LogTextBox türü (1) TextView alt sınıfına, (2) TextView.DefaultMovementMethod'u geçersiz kılarsa ve (3) XML aracılığıyla bu sınıfın bir örneğini etkinleştirirse, geçersiz kılınan DefaultMovementMethod özelliği ACW oluşturucusunun yürütme şansı olmadan çağrılır ve C# oluşturucusunun yürütme şansı olmadan önce gerçekleşir.

Bu, ACW LogTextBox örneği yönetilen kodu ilk kez girdiğinde LogTextView(IntPtr, JniHandleOwnership) oluşturucu aracılığıyla LogTextBox örneğinin örneğini oluşturarak ve ardından ACW oluşturucu yürütürken aynı örnekte LogTextBox(Context, IAttributeSet, int) oluşturucuyu çağırarak desteklenir.

Olay sırası:

  1. Düzen XML'i bir ContentView'a yüklenir.

  2. Android, Düzen nesne grafiğini başlatır ve LogTextBox için ACW olan monodroid.apidemo.LogTextBox örneğinin örneğini oluşturur.

  3. monodroid.apidemo.LogTextBox oluşturucu android.widget.TextView oluşturucusunu yürütür.

  4. TextView oluşturucu monodroid.apidemo.LogTextBox.getDefaultMovementMethod() öğesini çağırır.

  5. monodroid.apidemo.LogTextBox.getDefaultMovementMethod(), Java.Lang.Object.GetObject<TextView> (handle, JniHandleOwnership.DoNotTransfer) öğesini çağıran TextView.n_GetDefaultMovementMethod() öğesini çağıran LogTextBox.n_getDefaultMovementMethod() öğesini çağırır .

  6. Java.Lang.Object.GetObject<TextView>() işleyicisi için karşılık gelen bir C# örneği olup olmadığını denetler. Varsa, döndürülür. Bu senaryoda yoktur, bu nedenle Object.GetObject<T>() bir tane oluşturmalıdır.

  7. Object.GetObject<T>(), LogTextBox(IntPtr, JniHandleOwneship) oluşturucuyu arar, çağırır, tanıtıcı ile oluşturulan örnek arasında bir eşleme oluşturur ve oluşturulan örneği döndürür.

  8. TextView.n_GetDefaultMovementMethod(), LogTextBox.DefaultMovementMethod özellik alıcısını çağırır.

  9. Denetim, yürütmeyi tamamlayan android.widget.TextView oluşturucusunun döndürür.

  10. Monodroid.apidemo.LogTextBox oluşturucu yürütülür ve TypeManager.Activate() çağrılır.

  11. LogTextBox(Context, IAttributeSet, int) oluşturucu , (7) içinde oluşturulan aynı örnekte yürütülür.

  12. (IntPtr, JniHandleOwnership) oluşturucu bulunamazsa System.MissingMethodException](xref:System.MissingMethodException) oluşturulur.

Erken Dispose() Çağrıları

JNI tanıtıcısı ile ilgili C# örneği arasında bir eşleme vardır. Java.Lang.Object.Dispose() bu eşlemeyi keser. Eşleme kesildikten sonra bir JNI tanıtıcısı yönetilen kod girerse Java Etkinleştirmesi gibi görünür ve (IntPtr, JniHandleOwnership) oluşturucu denetlenip çağrılır. Oluşturucu yoksa bir özel durum oluşturulur.

Örneğin, aşağıdaki Yönetilen Çağrılabilen Sarmalayıcı alt sınıfı göz önünde bulundurulduğunda:

class ManagedValue : Java.Lang.Object {

    public string Value {get; private set;}

    public ManagedValue (string value)
    {
        Value = value;
    }

    public override string ToString ()
    {
        return string.Format ("[Managed: Value={0}]", Value);
    }
}

Bir örnek oluşturursak, dispose() ve Managed Callable Wrapper'ın yeniden oluşturulmasına neden olur:

var list = new JavaList<IJavaObject>();
list.Add (new ManagedValue ("value"));
list [0].Dispose ();
Console.WriteLine (list [0].ToString ());

Program ölecek:

E/mono    ( 2906): Unhandled Exception: System.NotSupportedException: Unable to activate instance of type Scratch.PrematureDispose.ManagedValue from native handle 4051c8c8 --->
System.MissingMethodException: No constructor found for Scratch.PrematureDispose.ManagedValue::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership)
E/mono    ( 2906):   at Java.Interop.TypeManager.CreateProxy (System.Type type, IntPtr handle, JniHandleOwnership transfer) [0x00000] in <filename unknown>:0
E/mono    ( 2906):   at Java.Interop.TypeManager.CreateInstance (IntPtr handle, JniHandleOwnership transfer, System.Type targetType) [0x00000] in <filename unknown>:0
E/mono    ( 2906):   --- End of inner exception stack trace ---
E/mono    ( 2906):   at Java.Interop.TypeManager.CreateInstance (IntPtr handle, JniHandleOwnership transfer, System.Type targetType) [0x00000] in <filename unknown>:0
E/mono    ( 2906):   at Java.Lang.Object.GetObject (IntPtr handle, JniHandleOwnership transfer, System.Type type) [0x00000] in <filename unknown>:0
E/mono    ( 2906):   at Java.Lang.Object._GetObject[IJavaObject] (IntPtr handle, JniHandleOwnership transfer) [0x00000

Alt sınıf bir (IntPtr, JniHandleOwnership) oluşturucu içeriyorsa, türün yeni bir örneği oluşturulur. Sonuç olarak örnek, yeni bir örnek olduğundan tüm örnek verilerini "kaybetmiş" gibi görünür. (Değer'in null olduğuna dikkat edin.)

I/mono-stdout( 2993): [Managed: Value=]

Java nesnesinin artık kullanılmayacağını bildiğiniz veya alt sınıfın örnek veri içermediğini ve bir (IntPtr, JniHandleOwnership) oluşturucu sağlandığını bildiğinizde yalnızca Yönetilen çağrılabilen sarmalayıcı alt sınıflarının Dispose() değeri sağlanır.

Uygulama Başlatma

Bir etkinlik, hizmet vb. başlatıldığında, Android önce etkinliği/hizmeti barındırmak için çalışan bir işlem olup olmadığını denetler. Böyle bir işlem yoksa yeni bir işlem oluşturulur, AndroidManifest.xml okunur ve /manifest/application/@android:name özniteliğinde belirtilen tür yüklenir ve örneği oluşturulur. Ardından, /manifest/application/provider/@android:name öznitelik değerleri tarafından belirtilen tüm türler örneği oluşturulur ve ContentProvider.attachInfo%28) yöntemi çağrılır. Xamarin.Android, mono ekleyerek buna takılır. Derleme işlemi sırasında AndroidManifest.xml için MonoRuntimeProvider ContentProvider . Mono. MonoRuntimeProvider.attachInfo() yöntemi Mono çalışma zamanını işleme yüklemekle sorumludur. Bu noktadan önce Mono kullanma girişimleri başarısız olur. ( Not: Bu nedenle, Uygulama örneği Mono başlatılmadan önce oluşturulduğundan Android.App.Application alt sınıfının (IntPtr, JniHandleOwnership) oluşturucu sağlaması gerekir.)

İşlem başlatma işlemi tamamlandıktan sonra, AndroidManifest.xml başlatacak etkinliğin/hizmetin/vb. sınıf adını bulmak için danışılır. Örneğin yüklenecek etkinliğin adını belirlemek için /manifest/application/activity/@android:name özniteliği kullanılır. Etkinlikler için bu tür android.app.Activity öğesini devralmalıdır. Belirtilen tür Class.forName() aracılığıyla yüklenir (türün bir Java türü olmasını gerektirir, bu nedenle Android Çağrılabilir Sarmalayıcılar) ve ardından örneği oluşturulur. Android Çağrılabilen Sarmalayıcı örneğinin oluşturulması, karşılık gelen C# türünün bir örneğinin oluşturulmasını tetikler. Android daha sonra Activity.onCreate(Bundle) öğesini çağırır. Bu, karşılık gelen Activity.OnCreate(Bundle) öğesinin çağrılmasına neden olur ve yarışlara çıkarsınız.