Burada açıklanan en iyi uygulamalar, özellikle bir API'yi tanımlamak veya API yüzeyleriyle etkileşim kurmak için AIDL kullanıldığında, AIDL arayüzlerini etkili bir şekilde ve arayüzün esnekliğine dikkat ederek geliştirme konusunda bir rehber işlevi görür.
Uygulamaların arka planda bir işlemde birbirleriyle arayüzleşmesi ya da sistemle arayüz oluşturması gerektiğinde bir API tanımlamak için AIDL kullanılabilir. AIDL ile uygulamalarda programlama arayüzü geliştirme hakkında daha fazla bilgi için Android Arayüz Tanımlama Dili (AIDL) bölümüne bakın. Uygulamadaki AIDL örnekleri için HAL'ler için AIDL ve Kararlı AIDL'ye bakın.
Sürüm oluşturma
AIDL API'nin 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
komutunu çalıştırın. API'nin bir istemcisi veya sunucusu yayınlandığında (örneğin, bir Mainline treninde) anlık görüntü almanız ve yeni bir sürüm oluşturmanız gerekir. Sistemden tedarikçi firmaya API'ler için bu durum yıllık platform revizyonuyla yapılmalıdır.
İzin verilen değişiklik türü hakkında daha fazla ayrıntı ve bilgi için Sürüm oluşturma arayüzleri bölümüne bakın.
API tasarım yönergeleri
Genel
1. Her şeyi belgeleyin
- Anlamları, bağımsız değişkenleri, yerleşik istisnaların kullanımı, hizmete özgü istisnalar ve dönüş değeri açısından her yöntemi belgeleyin.
- Her arayüzü anlam açısından belgeleyin.
- Enum ve sabit değerlerin anlamsal anlamını belgeleyin.
- Uygulayan kişi için net olmayan noktaları belgeleyin.
- Uygun yerlere örnekler verin.
2. Dış çizgi
Türler için deve büyük/küçük harf, yöntemler, alanlar ve bağımsız değişkenler için de alt büyük/küçük harf kullanın. Örneğin, ayrıştırılabilir tür için MyParcelable
, bağımsız değişken için anArgument
. Kısaltmalar için kelime kısaltmasını kullanabilirsiniz (NFC
-> Nfc
).
[-Wconst-name] Enum değerleri ve sabitleri ENUM_VALUE
ve CONSTANT_NAME
olmalıdır
Arayüzler
1. Adlandırma
[-Winterface-name] Arayüz adı I
ile başlamalıdır (ör. IFoo
).
2. Kimlik tabanlı "nesneler" içeren büyük arayüzlerden kaçının
Belirli bir API ile ilgili çok sayıda çağrı olduğunda alt arayüzleri tercih edin. Bu durum, aşağıdaki avantajları sağlar:
- İstemci veya sunucu kodunun daha kolay anlaşılmasını sağlar
- Nesnelerin yaşam döngüsünü basitleştirir
- Bağlayıcıların dövülemez olmasından faydalanır.
Önerilmez: Kimlik tabanlı nesnelere sahip tek, büyük 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: Bağımsız 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ü ve iki yönlü yöntemleri bir arada kullanmayın.
[-Wmixed-oneway] İş parçacığı oluşturma modelinin istemciler ve sunucular için anlaşılmasını karmaşık hale getireceğinden, tek yönlü olmayan yöntemlerle tek yönlü çalışmayın. Özellikle, belirli bir arayüzün istemci kodunu okurken her bir yöntemin engellenip engellenmeyeceğini aramanız gerekir.
4. Durum kodları döndürmekten kaçının
Tüm AIDL yöntemlerinin örtülü durum döndürme kodu olduğundan, yöntemlerde durum kodları dönüş değeri olarak kullanmaktan kaçınılmalıdır. ServiceSpecificException
veya EX_SERVICE_SPECIFIC
sayfasına göz atın. Geleneksel olarak bu değerler, AIDL arayüzünde sabit değer olarak tanımlanır. Daha ayrıntılı bilgiyi AIDL arka uçlarının hata işleme bölümünde bulabilirsiniz.
5. Çıkış parametreleri olarak zararlı olarak kabul edilen diziler
[-Wout-array] void foo(out String[] ret)
gibi dizi çıkış parametrelerine sahip yöntemler genellikle kötüdür. Bunun nedeni, çıkış dizisi boyutunun Java'da istemci tarafından bildirilmesi ve ayrılması gerektiği, dolayısıyla dizi çıkışının boyutu sunucu tarafından seçilmemesidir. Bu istenmeyen davranış, dizilerin Java'da çalışma şeklinden kaynaklanır (yeniden ayrılamazlar). Bunun yerine String[] foo()
gibi API'leri tercih edin.
6. Giriş parametrelerinden kaçının
[-Winout-parametresi] in
parametreleri bile out
parametrelerine benzediğinden bu durum istemcilerin kafasını karıştırabilir.
7. Out ve inout @nullable dizi olmayan parametrelerden kaçının
[-Wout-nullable] Java arka ucu, diğer arka uçlar @nullable
ek açıklamasını işlemediği için out/inout @nullable T
arka uçlar arasında tutarsız davranışlara neden olabilir. Örneğin, Java olmayan arka uçlar @nullable
parametresini null olarak ayarlayabilir (C++'ta std::nullopt
olarak ayarlayabilir) ancak Java istemcisi bunu null olarak okuyamaz.
Yapılandırılmış parseller
1. Ne zaman kullanılır?
Gönderilecek birden fazla veri türünün olduğu yapılandırılmış ayrıştırıcıları kullanın.
Ayrıca, tek bir veri türünüz varsa ancak gelecekte bu veri türünü genişletmeniz gerekeceğini düşünüyorsanız bu yöntemi tercih edebilirsiniz. Örneğin, String username
kullanmayın. Aşağıdaki gibi genişletilebilir bir ayrıştırılabilir öğe kullanın:
parcelable User {
String username;
}
Böylece, gelecekte bu süreyi aşağıdaki gibi uzatabilirsiniz:
parcelable User {
String username;
int id;
}
2. Varsayılanları açıkça belirtin
[-Wexplicit-default, -Wenum-explicit-default] Alanlar için açık varsayılan değerler sağlayın.
Yapılandırılmamış parseller
1. Ne zaman kullanılır?
Yapılandırılmamış parseller Java'da @JavaOnlyStableParcelable
ile, NDK arka ucunda ise @NdkOnlyStableParcelable
ile kullanılabilir. Bunlar genellikle yapılandırılamayan eski ve
mevcut parsellerdir.
Sabitler ve numaralandırmalar
1. Bit alanları sabit alanlar kullanmalıdır
Bit alanları sabit alanlar kullanmalıdır (örneğin, bir arayüzde const int FOO = 3;
).
2. Sıralamalar kapalı kümeler olmalıdır.
Sıralamalar kapalı kümeler olmalıdır. Not: Enum öğeleri yalnızca arayüz sahibi ekleyebilir. Tedarikçilerin veya OEM'lerin bu alanları genişletmesi gerekiyorsa alternatif bir mekanizma gerekir. Mümkün olduğunda, yukarı dönük tedarikçi işlevselliği tercih edilmelidir. Bununla birlikte, bazı durumlarda özel tedarikçi firma değerlerine bu yöntemle izin verilebilir (ancak tedarikçi firmaların, AIDL'nin kendisini geliştirecek bir mekanizmaya sahip olmaları gerekir; birbirleriyle çelişememeleri ve üçüncü taraf uygulamalarında bu değerler kullanılmamalıdır).
3. "NUM_ELEMENTS" gibi değerlerden kaçının
Sıralamalar sürümlü olduğu için kaç değerin mevcut olduğunu gösteren değerlerden kaçınılmalıdır. C++'ta bu sorun, enum_range<>
ile çözülebilir. Pas için enum_values()
değerini kullanın. Java'da henüz bir çözüm yok.
Önerilmez: Numaralı değerler kullanılması
@Backing(type="int")
enum FruitType {
APPLE = 0,
BANANA = 1,
MANGO = 2,
NUM_TYPES, // BAD
}
4. Gereksiz ön eklerden ve son eklerden kaçının
[-Wredunt-name] Sabit değerlerde ve numaralandırıcılarda gereksiz veya yinelenen önekler ve sonekler kullanmaktan kaçının.
Önerilmez: Gereksiz bir önek kullanılması
enum MyStatus {
STATUS_GOOD,
STATUS_BAD // BAD
}
Önerilen: Sıralamayı doğrudan adlandırma
enum MyStatus {
GOOD,
BAD
}
Dosya Açıklayıcı
[-Wfile-descriptor] FileDescriptor
öğesinin bağımsız değişken olarak veya AIDL arayüz yönteminin döndürülen değeri olarak kullanılması önerilmez. Bu durum, özellikle AIDL Java'da uygulandığında, dikkatli bir şekilde ele alınmadığı takdirde dosya tanımlayıcısı sızıntısına neden olabilir. Temel olarak, bir FileDescriptor
kabul ederseniz artık kullanılmadığında bunu manuel olarak kapatmanız gerekir.
FileDescriptor
, otomatik olarak kapatılabilen unique_fd
ile eşlendiğinden yerel arka uçlarda güvendesiniz. Ancak kullanacağınız arka uç dilinden bağımsız olarak, gelecekte arka uç dilini değiştirme özgürlüğünüzü sınırlandıracağı için FileDescriptor
KULLANMAYIN.
Bunun yerine, otomatik kapatılabilen ParcelFileDescriptor
özelliğini kullanın.
Değişken birimler
Değişken birimlerin ada eklendiğinden emin olun. Böylece, birimlerin belgelere referansta bulunmadan iyi tanımlanmasını ve anlaşılmasını sağlayabilirsiniz.
Ö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ı göstermelidir
Zaman damgaları, 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;