Xamarin. Android API tasarım Ilkeleri

Mono 'nın parçası olan temel temel sınıf kitaplıklarına ek olarak Xamarin. Android, geliştiricilerin Mono ile yerel Android uygulamaları oluşturmalarına olanak tanımak için çeşitli Android API 'Leri bağlamalarıyla birlikte gelir.

Xamarin. Android ' in temel tarafında, C# dünyasını Java dünyasına bağlayan ve geliştiricilere C# veya diğer .NET dillerinden Java API 'Lerine erişim sağlayan bir birlikte çalışma altyapısı vardır.

Tasarım İlkeleri

Bunlar, Xamarin. Android bağlaması için bazı tasarım ilkelerimlerimize yöneliktir

  • .NET Framework tasarım yönergelerineuygun.

  • Geliştiricilerin Java sınıflarını alt sınıflara kullanmasına izin verin.

  • Alt sınıf C# standart yapıları ile çalışmalıdır.

  • Varolan bir sınıftan türet.

  • Taban oluşturucuyu zincire çağırın.

  • Geçersiz kılma yöntemleri C# ' nin geçersiz kılma sistemi ile yapılmalıdır.

  • Sık kullanılan Java görevlerini kolay ve zor Java görevlerini mümkün hale getirin.

  • JavaBean özelliklerini C# özellikleri olarak kullanıma sunun.

  • Kesin tür belirtilmiş bir API 'YI kullanıma sunma:

    • Tür güvenliğini artırın.

    • Çalışma zamanı hatalarını en aza indirir.

    • Dönüş türlerinde IDE IntelliSense 'i alın.

    • IDE açılan belgelerine izin verir.

  • API 'lerin IDE 'de araştırmasını teşvik edin:

    • Java ClassLib pozlamasını en aza Indirmek için çerçeve alternatifleri kullanın.

    • Uygun ve uygulanabilir olduğunda tek yöntem arabirimleri yerine C# temsilcilerini (lambda Das, anonim yöntemler ve System. Delegate) kullanıma sunun.

    • Rastgele Java kitaplıklarını ( Android. Runtime. JNIEnv) çağırmak için bir mekanizma sağlar.

Bütünleştirilmiş Kodlar

Xamarin. Android, Monomobile profilinioluşturan bir dizi derleme içerir. Derlemeler sayfasında daha fazla bilgi bulunur.

Android platformunun bağlamaları derlemede yer alır Mono.Android.dll . Bu derleme, Android API 'Leri tüketen ve Android Runtime VM ile iletişim kuran tüm bağlamayı içerir.

Bağlama tasarımı

Koleksiyonlar

Android API 'Leri, listeler, kümeler ve haritalar sağlamak için Java. util koleksiyonlarını kapsamlı olarak kullanır. Bağlamamız içindeki System. Collections. Generic arabirimlerini kullanarak bu öğeleri kullanıma sunuyoruz. Temel eşlemeler şunlardır:

Bu türlerin daha hızlı bir şekilde sıralamasını kolaylaştırmak için yardımcı sınıflar sunuyoruz. Mümkün olduğunda, veya gibi Framework tarafından sunulan uygulama yerine bu sağlanmış koleksiyonları kullanmanızı öneririz List<T>Dictionary<TKey, TValue> . Android. Runtime uygulamaları, yerel bir Java koleksiyonunu dahili olarak kullanır ve bu nedenle, BIR Android API üyesine geçiş yaparken yerel bir koleksiyona kopyalama ve kaynaktan kopyalamaya gerek yoktur.

Herhangi bir arabirim uygulamasını, bu arabirimi kabul eden bir Android yöntemine geçirebilirsiniz, örn. List<int>List<int> oluşturucusuna geçiş yapabilirsiniz. Ancak, Android. Runtime uygulamaları hariç tüm uygulamalarda listenin mono VM 'den Android çalışma zamanı VM 'sine kopyalanması gerekir. Liste daha sonra Android çalışma zamanı içinde değiştirilirse (örn. Arrayadapter T 'yi çağırarak) > . Ekle (T) yöntemi), > Bir JavaList<int> kullanılmışsa, bu değişiklikler görünür olur.

İşlemindeki, yukarıda listelenen yardımcı sınıftanbiri olmayan koleksiyonlar arabirim uygulamaları yalnızca [ın] sıralaması:

// This fails:
var badSource  = new List<int> { 1, 2, 3 };
var badAdapter = new ArrayAdapter<int>(context, textViewResourceId, badSource);
badAdapter.Add (4);
if (badSource.Count != 4) // true
    throw new InvalidOperationException ("this is thrown");

// this works:
var goodSource  = new JavaList<int> { 1, 2, 3 };
var goodAdapter = new ArrayAdapter<int> (context, textViewResourceId, goodSource);
goodAdapter.Add (4);
if (goodSource.Count != 4) // false
    throw new InvalidOperationException ("should not be reached.");

Özellikler

Java yöntemleri uygun olduğunda özelliklere dönüştürülür:

  • Java yöntemi çifti T getFoo() ve void setFoo(T)Foo özelliğine dönüştürülür. Örnek: Activity. amaç.

  • Java yöntemi getFoo() salt okunurdur foo özelliğine dönüştürülür. Örnek: Context. PackageName.

  • Yalnızca set özellikleri oluşturulmaz.

  • Özellik türü bir dizi olacaksa Özellikler oluşturulmaz.

Olaylar ve dinleyiciler

Android API 'Leri, Java 'nın üzerine kurulmuştur ve bileşenleri, olay dinleyicilerini aramak için Java düzenine uyar. Bu kalıp, kullanıcının anonim bir sınıf oluşturmasını ve geçersiz kılmak için yöntemler belirtmesini gerektirdiğinden, örneğin, Java ile Android 'de nasıl yapılacağı gibi bir şey olduğunu eğilimi gösterir.

final android.widget.Button button = new android.widget.Button(context);

button.setText(this.count + " clicks!");
button.setOnClickListener (new View.OnClickListener() {
    public void onClick (View v) {
        button.setText(++this.count + " clicks!");
    }
});

Olaylar kullanılarak C# ' de eşdeğer kod şöyle olacaktır:

var button = new Android.Widget.Button (context) {
    Text = string.Format ("{0} clicks!", this.count),
};
button.Click += (sender, e) => {
    button.Text = string.Format ("{0} clicks!", ++this.count);
};

Yukarıdaki mekanizmaların her ikisinin de Xamarin. Android ile kullanılabilir olduğunu unutmayın. Bir dinleyici arabirimi uygulayabilir ve View. SetOnClickListener ile iliştirebilirsiniz ya da her zamanki C# paradigmalarına aracılığıyla oluşturulan bir temsilciyi tıklama olayına ekleyebilirsiniz.

Dinleyici geri çağırma yönteminin void dönüşi olduğunda, bir EventHandler TEventArgs > temsilcisine dayalı API öğeleri oluşturacağız. Bu dinleyici türleri için yukarıdaki örnek gibi bir olay oluşturacağız. Ancak, dinleyici geri çağırması void olmayan ve Boole olmayan bir değer döndürürse, Events ve EventHandlers kullanılmaz. Bunun yerine, geri aramanın imzası için belirli bir temsilci oluşturun ve olaylar yerine özellikler ekleyin. Bunun nedeni, temsilci çağırma sırası ve dönüş işlemesi ile ilgilenildir. Bu yaklaşım, Xamarin. iOS API 'SI ile yapılan şeyi yansıtır.

C# olayları veya özellikleri yalnızca Android olay kayıt yöntemi ise otomatik olarak oluşturulur:

  1. set, Örn. set.

  2. Bir void dönüş türüne sahiptir.

  3. Yalnızca bir parametre kabul eder, parametre türü bir arabirimdir, arabirimin yalnızca bir yöntemi vardır ve arabirim adı Listener , örneğin, Listenerile biter.

Ayrıca, dinleyici arabirimi yönteminin voidyerine Boolean değeri varsa, oluşturulan EventArgs alt sınıfı bir işlenmiş özellik içerir. İşlenmiş özelliğinin değeri, dinleyici yöntemi için dönüş değeri olarak kullanılır ve varsayılan olarak öğesine ayarlanır .

Örneğin, Android View. setOnKeyListener () yöntemi View. onkeylistener arabirimini kabul eder ve View. onkeylistener. onkey (görünüm, int, keyevent) yönteminin bir Boole dönüş türü vardır. Xamarin. Android, bir EventHandler görünümü. KeyEventArgs olan karşılık gelen bir View. KeyPress olayını oluşturur. ' De KeyEventArgs sınıfının, View. Onkeylistener. onkey () yöntemi için dönüş değeri olarak kullanılan bir View. KeyEventArgs. işlenmiş özelliği vardır.

Temsilci tabanlı bağlantıyı açığa çıkarmak için diğer yöntemler ve oluşturucuları için aşırı yüklemeler eklemek istiyorduk. Ayrıca, birden çok geri çağırma içeren dinleyiciler, tek tek geri çağırmaların uygun şekilde uygulanmadığını belirlemede bazı ek inceleme gerektirir, bu nedenle bunları, tanımlandıkları şekilde dönüştürüyoruz. Karşılık gelen bir olay yoksa, dinleyiciler C# dilinde kullanılmalıdır, ancak lütfen ilgilenmeniz gereken temsilci kullanımı olduğunu düşündüğünüzden emin olun. Ayrıca, "dinleyici" soneki olmadan bazı arabirimlerin dönüştürmelerinde, bir temsilci alternatifi avantajdan faydalanırız.

Tüm dinleyici arabirimleri şunları uygularAndroid.Runtime.IJavaObject arabirim, bağlamanın uygulama ayrıntıları nedeniyle bu arabirimi uygulamalıdır. Bu işlem, bir Java. lang. Object alt sınıfı veya bir Android etkinliği gibi başka bir sarmalanmış Java nesnesi üzerinde dinleyici arabirimi uygulayarak yapılabilir.

Runnanak 'lar

Java, bir yetkilendirme mekanizması sağlamak için Java. lang. runbir arabirimini kullanır. Java. lang. Thread sınıfı bu arabirimin bir önemli tüketicisidir. Android, arabirimi API 'de de yayımlamıştır. Activity. runOnUiThread () ve View.Post () , önemli örnekleridir.

RunnableArabirim tek bir void yöntemi içerir, Runnable. Bu nedenle, bir System. Action temsilcisi olarak C# ' de bağlamak üzere kendisini uzunlukları. Bağlamada Action bir parametre kabul eden Runnable , örneğin, Action ve Runnableyerel API 'sinde bulunan tüm API üyeleri için bir parametre kabul eden aşırı yüklemeler sağladık.

Birkaç tür arabirimi kullandığından ve bu nedenle doğrudan runnatik olarak geçirilebileceğinizden, Nunınidar aşırı yüklerini değiştirmek yerine yerinde kalmadı.

İç sınıflar

Java 'da iki farklı tür iç içe sınıfvardır: statik iç içe sınıflar ve statik olmayan sınıflar.

Java statik iç içe yerleştirilmiş sınıfları C# iç Içe türleriyle aynıdır.

İç sınıflarolarak da bilinen statik olmayan iç içe sınıflar önemli ölçüde farklıdır. Bunların kapsayan türünün bir örneğine örtük bir başvuru içerirler ve statik üye (Bu genel bakış kapsamı dışında diğer farklılıklar) içeremez.

Bağlama ve C# kullanımına geldiğinde, statik iç içe sınıflar normal iç içe türler olarak değerlendirilir. Bu arada, iç sınıfların iki önemli farkı vardır:

  1. Kapsayan türe örtük başvuru açıkça bir oluşturucu parametresi olarak sağlanmalıdır.

  2. Bir iç sınıftan devralındığında, iç sınıf temel iç sınıfın kapsayan türünden devralan bir tür içinde iç içe olmalıdır ve türetilmiş tür bir tür oluşturucuyu içeren C# ile aynı türde bir Oluşturucu sağlamalıdır.

Örneğin, Android. Service. duvar kağıdı. duvar Paperservice. Engine iç sınıfını göz önünde bulundurun. Bu bir iç sınıf olduğu için, WallpaperService.Engine() oluşturucusu bir WallpaperService örneğine başvuru alır (parametre alan Java WallpaperService.Engine() oluşturucus una karşıtlığı ve karşılaştırması).

Bir iç sınıfın türetme örneği CubeWallpaper.CubeEngine'tir:

class CubeWallpaper : WallpaperService {
    public override WallpaperService.Engine OnCreateEngine ()
    {
        return new CubeEngine (this);
    }

    class CubeEngine : WallpaperService.Engine {
        public CubeEngine (CubeWallpaper s)
                : base (s)
        {
        }
    }
}

içinde nasıl iç içe geçmiş olduğunu unutmayın, içeren sınıfından devralır ve bildirim türünü (bu durumda) alan bir oluşturucuya (yukarıda belirtildiği CubeWallpaper.CubeEngineCubeWallpaperCubeWallpaperWallpaperService.EngineCubeWallpaper.CubeEngineCubeWallpaper gibi) sahip olur.

Arabirimler

Java arabirimleri üç üye kümesi içerebilir ve ikisi C# ile ilgili sorunlara neden olur:

  1. Yöntemler

  2. Türler

  3. Alanlar

Java arabirimleri iki türe çevrilir:

  1. Yöntem bildirimlerini içeren bir (isteğe bağlı) arabirim. Bu arabirim Java arabirimiyle aynı adı içerir, ancak aynı zamanda 'I' ön eke sahiptir.

  2. Java arabiriminde bildirilen alanları içeren bir (isteğe bağlı) statik sınıf.

İç içe geçmiş türler, iç içe geçmiş türler yerine kapsayan arabirimin ve kapsayan arabirim adının ön ek olarak yer alan bir arabirimle eşleşmesi için "yeniden konumlanmış"dır.

Örneğin, android.os.Able arabirimini göz önünde bulundurabilirsiniz. Able arabirimi yöntemler, iç içe geçmiş türler ve sabitler içerir. Uygun arabirim yöntemleriAndroid.OS.IParcelable arabirimine yerleştirilir. Girilebilir arabirim sabitleri Android.OS.AbleConsts türüne yerleştirilir. İç içe android.os.Genericable.ClassLoaderCreator > T ve > türleri şu anda genel tür desteğimizin sınırlamaları nedeniyle bağlı değildir; destekleniyorsa < ve > arabirimleri olarak mevcut olacaktır. Örneğin, iç içe geçmiş android.os.IBinder.DeathRecipient arabirimi Android.OS.IBinderDeathRecipient arabirimi olarak bağlandı.

Not

Xamarin.Android 1.9'dan itibaren Java kodunun taşınabilirliği basitleştirmek için Java arabirim sabitleri yineleniyor. Bu, Android sağlayıcı arabirimi sabitlerini kullanarak Java kodunun taşınabilirlik performansını artırmaya yardımcı olur.

Yukarıdaki türlere ek olarak dört değişiklik daha vardır:

  1. Sabitleri içermesi için Java arabirimiyle aynı adı içeren bir tür oluşturulur.

  2. Arabirim sabitleri içeren türler, uygulanan Java arabirimlerinden gelen tüm sabitleri de içerir.

  3. Sabitler içeren bir Java arabirimi uygulayan tüm sınıflar, uygulanan tüm arabirimlerden sabitleri içeren yeni bir iç içe InterfaceConsts türüne sahip olur.

  4. Consts türü artık kullanılmıyor.

android.os.Able arabirimi için bu, artık sabitleri içeren bir Android.OS.Able türü olduğu anlamına gelir. Örneğin, Parcelable.CONTENTS_FILE_DESCRIPTORsabiti, YerLeştirilebilirConsts.ContentsFileDescriptor sabiti olarak değil,Able.ContentsFileDescriptorsabiti olarak bağlanacak.

Henüz daha fazla sabit içeren diğer arabirimleri uygulayan sabitler içeren arabirimler için artık tüm sabitlerin birliği oluşturulur. Örneğin, android.provider.MediaStore.Video.VideoColumns arabirimi android.provider.MediaStore.MediaColumns arabirimini kullanır. Ancak, 1.9'dan önce Android.Provider.MediaStore.Video.VideoColumnsConsts türünün Android.Provider.MediaStore.MediaColumnsConstsüzerinde bildirilen sabitlere erişmesi mümkün değildir. Sonuç olarak MediaStore.Video.VideoColumns.TITLE Java ifadesinin, çok fazla Java belgesi okumadan bulmanın zor olduğu MediaStore.Video.MediaColumnsConsts.Title C# ifadesine bağlı olması gerekir. 1.9'da eşdeğer C# ifadesi MediaStore.Video.VideoColumns.Title olur.

Ayrıca JavaAble arabirimini uygulayan android.os.Bundletürünü de göz önünde bulundurabilirsiniz. Arabirimi uygulayan bu arabirimde yer alan tüm sabitlere Paket türü aracılığıyla "erişilebilir". Örneğin, Bundle.CONTENTS_FILE_DESCRIPTOR bir Java ifadesidir. Daha önce, bu ifadeyi C# ile bağlantı noktası olarak uygulamak için, uygulamanın hangi türden geldiğini görmek için uygulanan tüm arabirimlere CONTENTS_FILE_DESCRIPTOR gerekirdi. Xamarin.Android 1.9'dan başlayarak sabitler içeren Java arabirimlerini uygulayan sınıflar, devralınan tüm arabirim sabitlerini içeren iç içe InterfaceConsts türüne sahip olur. Bu, dosyanın Bundle.InterfaceConsts.ContentsFileDescriptor'Bundle.CONTENTS_FILE_DESCRIPTOR çevirisine olanak sağlar.

Son olarak, Yeni eklenen InterfaceConsts iç içe türleri dışında Android.OS.ObsoleteableConsts gibi consts soneki olan türler artık Geçersizdir. Bunlar Xamarin.Android 3.0'da kaldırılacaktır.

Kaynaklar

Görüntüler, düzen açıklamaları, ikili bloblar ve dize sözlükleri uygulamanıza kaynak dosyaları olarak dahil olabilir. Çeşitli Android API'leri doğrudan görüntüler, dizeler veya ikili bloblarla ilgilenmek yerine kaynak kimlikleri üzerinde çalışacak şekilde tasarlanmıştır.

Örneğin, kullanıcı arabirimi düzeni ( ), uluslararası bir tablo dizesi ( ) ve bazı simgeler ( ) içeren örnek bir Android uygulaması, kaynaklarını uygulamanın "Kaynaklar" dizininde main.axmlstrings.xmldrawable-*/icon.png tutabilirsiniz:

Resources/
    drawable-hdpi/
        icon.png

    drawable-ldpi/
        icon.png

    drawable-mdpi/
        icon.png

    layout/
        main.axml

    values/
        strings.xml

Yerel Android API'leri doğrudan dosya adlarına sahip değildir, bunun yerine kaynak kimlikleri üzerinde çalışır. Kaynakları kullanan bir Android uygulamasını derleyeci, derleme sistemi kaynakları dağıtım için paketler ve dahil edilen kaynakların her biri için belirteçleri içeren adlı Resource bir sınıf üretir. Örneğin, yukarıdaki Kaynaklar düzeni için R sınıfı bunu ortaya çıkarır:

public class Resource {
    public class Drawable {
        public const int icon = 0x123;
    }

    public class Layout {
        public const int main = 0x456;
    }

    public class String {
        public const int first_string = 0xabc;
        public const int second_string = 0xbcd;
    }
}

Ardından, dosyasına başvuru yapmak veya dosyaya başvuru yapmak ya da sözlük dosyasındaki Resource.Drawable.icondrawable/icon.png ilk Resource.Layout.mainlayout/main.xmlResource.String.first_string dizeye başvuru yapmak için kullanabilirsiniz. values/strings.xml

Sabitler ve Numaralandırmalar

Yerel Android API'lerinde, int'in ne anlama geldiğini belirlemek için sabit bir alana eşlenmiş olması gereken bir int alan veya dönüş birçok yöntemi vardır. Bu yöntemleri kullanmak için kullanıcının hangi sabitlerin uygun değerler olduğunu (idealden küçük) görmek için belgelere başvurması gerekir.

Örneğin Activity.requestWindowFeature(int featureID) kullanın.

Bu durumlarda, ilgili sabitleri bir .NET sabitlemesinde birlikte gruplama ve bunun yerine sabitleri almak için yöntemini yeniden eşlemeye çalışıyoruz. Bunu yaparak olası değerleri IntelliSense'e sunabileceksiniz.

Yukarıdaki örnek şu olur: Activity.RequestWindowFeature(WindowFeatures featureId).

Bu, hangi sabitlerin birlikte ait olduğunu ve hangi API'lerin bu sabitleri tükettiği hakkında bilgi sahibi olmak için el ile sızan bir işlem olduğunu unutmayın. Lütfen API'de kullanılan sabitler için sabitler için sabitler olarak daha iyi ifade edmelidir.