Burada özetlenen en iyi uygulamalar, özellikle AIDL bir API tanımlamak veya API yüzeyleriyle etkileşimde bulunmak için kullanıldığında, AIDL arayüzlerini etkili bir şekilde ve arayüzün esnekliğine dikkat ederek geliştirmek için bir kılavuz olarak hizmet eder.
AIDL, uygulamaların bir arka plan işleminde birbirleriyle arayüz oluşturması veya sistemle arayüz oluşturması gerektiğinde bir API tanımlamak için kullanılabilir. AIDL ile uygulamalarda programlama arayüzleri geliştirme hakkında daha fazla bilgi için bkz. Android Arayüz Tanımlama Dili (AIDL) . Uygulamadaki AIDL örnekleri için bkz. HAL'ler için AIDL ve Stabil AIDL .
Sürüm oluşturma
Bir AIDL API'sinin geriye dönük uyumlu her anlık görüntüsü bir sürüme karşılık gelir. Anlık görüntü almak için m <module-name>-freeze-api
çalıştırın. API'nin bir istemcisi veya sunucusu yayınlandığında (örneğin bir ana hat treninde), bir anlık görüntü almanız ve yeni bir sürüm oluşturmanız gerekir. Sistemden satıcıya API'ler için bu, yıllık platform revizyonunda gerçekleşmelidir.
İzin verilen değişiklik türleri hakkında daha fazla ayrıntı ve bilgi için bkz. Sürüm oluşturma arayüzleri .
API tasarım yönergeleri
Genel
1. Her şeyi belgeleyin
- Anlambilimi, argümanları, yerleşik istisnaların kullanımı, hizmete özel istisnalar ve dönüş değeri açısından her yöntemi belgeleyin.
- Anlamsal açıdan her arayüzü belgeleyin.
- Numaralandırmaların ve sabitlerin anlamsal anlamını belgeleyin.
- Bir uygulayıcı için belirsiz olabilecek her şeyi belgeleyin.
- İlgili yerlerde örnekler verin.
2. Muhafaza
Türler için üst deve harfini ve yöntemler, alanlar ve argümanlar için alt deve harfini kullanın. Örneğin, parçalanabilir bir tür için MyParcelable
ve bir bağımsız değişken için anArgument
. Kısaltmalar için kısaltmayı bir kelime olarak düşünün ( NFC
-> Nfc
).
[-Wconst-name] Numaralandırma değerleri ve sabitleri ENUM_VALUE
ve CONSTANT_NAME
olmalıdır
Arayüzler
1. Adlandırma
[-Winterface-name] Bir arayüz adı I
like IFoo
ile başlamalıdır.
2. Kimlik tabanlı "nesneler" içeren büyük arayüzden kaçının
Belirli bir API ile ilgili çok sayıda çağrı olduğunda alt arayüzleri tercih edin. Bu, aşağıdaki faydaları sağlar: - İstemci/sunucu kodunun anlaşılmasını kolaylaştırır - Nesnelerin yaşam döngüsünü kolaylaştırır - Bağlayıcıların taklit edilemez olmasının avantajından yararlanır.
Tavsiye edilmiyor: Kimlik tabanlı nesnelere sahip tek, geniş bir arayüz
interface IManager {
int getFooId();
void beginFoo(int id); // clients in other processes can guess an ID
void opFoo(int id);
void recycleFoo(int id); // ownership not handled by type
}
Önerilen: Bireysel alt arayüzler
interface IManager {
IFoo getFoo();
}
interface IFoo {
void begin(); // clients in other processes can't guess a binder
void op();
}
3. Tek yönlü yöntemlerle çift yönlü yöntemleri karıştırmayın
[-Wmixed-oneway] Tek yönlü olmayan yöntemlerle tek yönlü yöntemleri karıştırmayın, çünkü bu, iş parçacığı modelinin anlaşılmasını istemciler ve sunucular için karmaşık hale getirir. Özellikle, belirli bir arayüzün istemci kodunu okurken, her yöntemin o yöntemin engellenip engellenmeyeceğini aramanız gerekir.
4. Durum kodlarını döndürmekten kaçının
Tüm AIDL yöntemlerinin örtülü bir durum dönüş kodu olduğundan, yöntemler dönüş değeri olarak durum kodlarından kaçınmalıdır. ServiceSpecificException
veya EX_SERVICE_SPECIFIC
bakın. Geleneksel olarak bu değerler AIDL arayüzünde sabitler olarak tanımlanır. Daha ayrıntılı bilgi AIDL Arka Uçlarının Hata işleme bölümündedir .
5. Çıkış parametreleri olarak diziler zararlı kabul edilir
[-Wout-array] void foo(out String[] ret)
gibi dizi çıkış parametrelerine sahip yöntemler genellikle kötüdür çünkü çıktı dizisi boyutunun Java'da istemci tarafından bildirilmesi ve tahsis edilmesi gerekir ve bu nedenle dizi çıktısının boyutu yapılamaz. sunucu tarafından seçilebilir. Bu istenmeyen davranış, dizilerin Java'da çalışma biçiminden kaynaklanmaktadır (yeniden tahsis edilemezler). Bunun yerine String[] foo()
gibi API'leri tercih edin.
6. Giriş parametrelerinden kaçının
[-Winout-parameter] Bu out
in
benzemektedir.
7. Out/inout @nullable dizi dışı parametrelerden kaçının
[-Wout-nullable] Diğer arka uçlar bunu yaparken Java arka ucu @nullable
ek açıklamasını işlemediğinden, out/inout @nullable T
arka uçlar arasında tutarsız davranışlara yol açabilir. Örneğin, Java dışı arka uçlar, out @nullable
parametresini null olarak ayarlayabilir (C++'da std::nullopt
olarak ayarlayarak), ancak Java istemcisi bunu null olarak okuyamaz.
Yapılandırılmış parsellenebilirler
1. Ne zaman kullanılmalı
Gönderecek birden fazla veri türünüzün olduğu yapılandırılmış parsellenebilirleri kullanın.
Veya şu anda tek bir veri türünüz varsa ancak gelecekte bunu genişletmeniz gerekeceğini düşünüyorsanız. Örneğin, String username
kullanmayın. Aşağıdaki gibi genişletilebilir bir parsellenebilir kullanın:
parcelable User {
String username;
}
Böylece gelecekte bunu aşağıdaki şekilde genişletebilirsiniz:
parcelable User {
String username;
int id;
}
2. Varsayılanları açıkça belirtin
[-Wexplicit-default, -Wenum-explicit-default] Alanlar için açık varsayılanlar sağlayın.
Yapılandırılmamış parsellenebilirler
1. Ne zaman kullanılmalı
Yapılandırılmış olmayan parsellenebilirler şu anda Java'da @JavaOnlyStableParcelable
ile ve NDK arka ucunda @NdkOnlyStableParcelable
ile mevcuttur. Genellikle bunlar kolayca yapılandırılamayan eski ve mevcut parsellenebilirlerdir.
Sabitler ve Numaralandırmalar
1. Bitfield'ler sabit alanları kullanmalıdır
Bit alanları sabit alanlar kullanmalıdır (örneğin, bir arayüzde const int FOO = 3;
).
2. Numaralandırmalar kapalı kümeler olmalıdır.
Numaralandırmalar kapalı kümeler olmalıdır. Not: yalnızca arayüz sahibi enum öğeleri ekleyebilir. Satıcıların veya OEM'lerin bu alanları genişletmesi gerekiyorsa alternatif bir mekanizmaya ihtiyaç vardır. Mümkün olduğunda, yukarı akışlı satıcı işlevselliği tercih edilmelidir. Ancak bazı durumlarda, özel satıcı değerlerine izin verilebilir (yine de satıcıların bunu sürümlendirecek bir mekanizmaya, belki de AIDL'ye sahip olmaları gerekir; birbirleriyle çakışmamaları gerekir ve bu değerler 3. parti uygulamalara maruz kalan).
3. "NUM_ELEMENTS" gibi değerlerden kaçının
Numaralandırmalar versiyonlu olduğundan, kaç değerin mevcut olduğunu gösteren değerlerden kaçınılmalıdır. C++'da bu durum enum_range<>
ile çözülebilir. Rust için enum_values()
işlevini kullanın. Java'da henüz bir çözüm yok.
Tavsiye edilmiyor: Numaralandırılmış değerlerin kullanılması
@Backing(type="int")
enum FruitType {
APPLE = 0,
BANANA = 1,
MANGO = 2,
NUM_TYPES, // BAD
}
4. Gereksiz önek ve son eklerden kaçının
[-Wredundant-name] Sabitlerde ve numaralandırıcılarda gereksiz veya yinelenen önek ve son eklerden kaçının.
Tavsiye edilmiyor: Gereksiz bir önek kullanma
enum MyStatus {
STATUS_GOOD,
STATUS_BAD // BAD
}
Önerilen: Numaralandırmayı doğrudan adlandırma
enum MyStatus {
GOOD,
BAD
}
Dosya Tanımlayıcı
[-Wfile-descriptor] FileDescriptor
bağımsız değişken olarak veya bir AIDL arabirim yönteminin dönüş değeri olarak kullanılması kesinlikle önerilmez. Özellikle AIDL Java'da uygulandığında, bu durum dikkatli bir şekilde ele alınmadığı takdirde dosya tanımlayıcı sızıntısına neden olabilir. Temel olarak, bir FileDescriptor
kabul ederseniz, artık kullanılmadığında onu manuel olarak kapatmanız gerekir.
Yerel arka uçlar için güvendesiniz çünkü FileDescriptor
otomatik olarak kapatılabilen unique_fd
ile eşleşir. Ancak kullanacağınız arka uç dili ne olursa olsun, FileDescriptor
hiç KULLANMAMAK akıllıca olacaktır çünkü bu, gelecekte arka uç dilini değiştirme özgürlüğünüzü sınırlayacaktır.
Bunun yerine, otomatik olarak kapatılabilen ParcelFileDescriptor
öğesini kullanın.
Değişken birimler
Değişken birimlerin isme dahil edildiğinden emin olun, böylece birimlerinin iyi tanımlanması ve belgelere başvurmaya gerek kalmadan anlaşılması sağlanır.
Örnekler
long duration; // Bad
long durationNsec; // Good
long durationNanos; // Also good
double energy; // Bad
double energyMilliJoules; // Good
int frequency; // Bad
int frequencyHz; // Good
Zaman damgaları referanslarını belirtmelidir
Zaman damgaları (aslında tüm birimler!) birimlerini ve referans noktalarını açıkça belirtmelidir.
Örnekler
/**
* Time since device boot in milliseconds
*/
long timestampMs;
/**
* UTC time received from the NTP server in units of milliseconds
* since January 1, 1970
*/
long utcTimeMs;