यहां बताए गए सबसे सही तरीके, एआईडीएल इंटरफ़ेस को असरदार तरीके से और इंटरफ़ेस के लचीलेपन पर ध्यान देकर बनाने के लिए गाइड के तौर पर काम करते हैं. खास तौर पर, जब एआईडीएल का इस्तेमाल किसी एपीआई को तय करने या एपीआई के प्लैटफ़ॉर्म के साथ इंटरैक्ट करने के लिए किया जाता है.
जब ऐप्लिकेशन को बैकग्राउंड प्रोसेस में एक-दूसरे के साथ इंटरफ़ेस करना हो या सिस्टम के साथ इंटरफ़ेस करना हो, तब एपीआई तय करने के लिए AIDL का इस्तेमाल किया जा सकता है. AIDL की मदद से ऐप्लिकेशन में प्रोग्रामिंग इंटरफ़ेस बनाने के बारे में ज़्यादा जानने के लिए, Android इंटरफ़ेस डेफ़िनिशन लैंग्वेज (AIDL) देखें. AIDL के इस्तेमाल के उदाहरणों के लिए, HALs के लिए AIDL और Stable AIDL देखें.
वर्शन
किसी AIDL API का हर पुराने वर्शन के साथ काम करने वाला स्नैपशॉट, किसी वर्शन से जुड़ा होता है.
स्नैपशॉट लेने के लिए, m <module-name>-freeze-api
चलाएं. जब भी एपीआई का कोई क्लाइंट या सर्वर रिलीज़ किया जाता है (उदाहरण के लिए, मेनलाइन ट्रेन में), तो आपको उसका स्नैपशॉट लेना होगा और नया वर्शन बनाना होगा. सिस्टम-टू-वेंडर एपीआई के लिए, यह हर साल प्लैटफ़ॉर्म में होने वाले बदलावों के साथ होना चाहिए.
अनुमति वाले बदलावों के प्रकार के बारे में ज़्यादा जानकारी और जानकारी के लिए वर्शन इंटरफ़ेस देखें.
एपीआई के डिज़ाइन से जुड़े दिशा-निर्देश
सामान्य सेटिंग
1. हर चीज़ का दस्तावेज़ बनाएं
- हर तरीके के सेमेंटेक्स, आर्ग्युमेंट, पहले से मौजूद अपवादों के इस्तेमाल, सेवा के हिसाब से अपवादों, और रिटर्न वैल्यू के लिए दस्तावेज़ बनाएं.
- हर इंटरफ़ेस के सिमेंटिक के लिए दस्तावेज़ बनाएं.
- एनम और कॉन्स्टेंट के सेमेटिक मतलब को दस्तावेज़ में शामिल करें.
- ऐसे सभी कामों को दस्तावेज़ में शामिल करें जो लागू करने वाले व्यक्ति को समझ न आएं.
- जहां ज़रूरी हो वहां उदाहरण दें.
2. केसिंग
टाइप के लिए अपर कैमल केसिंग और तरीकों, फ़ील्ड, और आर्ग्युमेंट के लिए लोअर कैमल केसिंग का इस्तेमाल करें. उदाहरण के लिए, पार्सल किए जा सकने वाले टाइप के लिए MyParcelable
और आर्ग्युमेंट के लिए anArgument
. संक्षिप्त शब्दों के लिए, संक्षिप्त शब्द को एक शब्द मानें (NFC
-> Nfc
).
[-Wconst-name] Enum वैल्यू और कॉन्सटेंट, ENUM_VALUE
और
CONSTANT_NAME
होने चाहिए
इंटरफ़ेस
1. इन्हें
[-Winterface-name] इंटरफ़ेस का नाम I
से शुरू होना चाहिए, जैसे कि IFoo
.
2. आईडी पर आधारित "ऑब्जेक्ट" वाले बड़े इंटरफ़ेस का इस्तेमाल न करें
किसी खास एपीआई से जुड़े कई कॉल होने पर, सब-इंटरफ़ेस का इस्तेमाल करें. इससे ये फ़ायदे मिलते हैं:
- क्लाइंट या सर्वर कोड को आसानी से समझने में मदद करता है
- इससे ऑब्जेक्ट के लाइफ़साइकल को आसान बनाया जा सकता है
- बाइंडर में मौजूद जानकारी को बदला नहीं जा सकता.
इसका सुझाव नहीं दिया जाता: आईडी पर आधारित ऑब्जेक्ट वाला एक बड़ा इंटरफ़ेस
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
}
इसका सुझाव दिया जाता है: अलग-अलग इंटरफ़ेस
interface IManager {
IFoo getFoo();
}
interface IFoo {
void begin(); // clients in other processes can't guess a binder
void op();
}
3. एकतरफ़ा और दोतरफ़ा तरीकों को एक साथ इस्तेमाल न करें
[-Wmixed-oneway] एकतरफ़ा तरीके को नॉन-वन-वे तरीकों के साथ न मिलाएं, क्योंकि इससे क्लाइंट और सर्वर के लिए, थ्रेडिंग मॉडल को समझना मुश्किल हो जाता है. खास तौर पर, किसी खास इंटरफ़ेस का क्लाइंट कोड पढ़ते समय, आपको हर एक तरीके को खोजना होगा कि वह तरीका ब्लॉक होगा या नहीं.
4. स्टेटस कोड दिखाने से बचें
मेथड को रिटर्न वैल्यू के तौर पर स्टेटस कोड इस्तेमाल करने से बचना चाहिए, क्योंकि सभी एआईडीएल मेथड में एक गुप्त स्टेटस रिटर्न कोड होता है. ServiceSpecificException
या
EX_SERVICE_SPECIFIC
देखें. आम तौर पर, इन वैल्यू को AIDL इंटरफ़ेस में स्थिरांक के तौर पर तय किया जाता है. ज़्यादा जानकारी के लिए, एआईडीएल बैकएंड के गड़बड़ी मैनेजमेंट सेक्शन पर जाएं.
5. आउटपुट पैरामीटर के तौर पर ऐरे को नुकसान पहुंचाने वाला माना जाता है
[-Wout-array] अरे आउटपुट पैरामीटर वाले मेथड, जैसे कि void foo(out String[] ret)
आम तौर पर खराब होते हैं. ऐसा इसलिए होता है, क्योंकि
आउटपुट अरे के साइज़ का एलान करना और उसे Java में क्लाइंट तय करना ज़रूरी है. इसलिए, सर्वर, आउटपुट अरे का साइज़ नहीं चुन सकता. यह गड़बड़ी इसलिए होती है, क्योंकि Java में ऐरे के काम करने का तरीका अलग होता है. इन ऐरे को फिर से असाइन नहीं किया जा सकता. इसके बजाय, String[] foo()
जैसे एपीआई का इस्तेमाल करें.
6. इनपुट और आउटपुट पैरामीटर इस्तेमाल करने से बचें
[-Winout-parameter] इससे क्लाइंट को भ्रम हो सकता है, क्योंकि in
पैरामीटर भी out
पैरामीटर जैसे दिखते हैं.
7. @nullable वाले ऐसे पैरामीटर इस्तेमाल न करें जो आउट और इनआउट पैरामीटर हों और ऐरे न हों
[-Wout-nullable] Java बैकएंड, @nullable
एनोटेशन को हैंडल नहीं करता,
जबकि अन्य बैकएंड ऐसा करते हैं. इसलिए, हो सकता है कि out/inout @nullable T
की वजह से, बैकएंड में अलग-अलग तरह की गड़बड़ियां दिखें. उदाहरण के लिए, नॉन-Java बैकएंड, आउट @nullable
पैरामीटर को शून्य पर सेट कर सकते हैं (C++ में, इसे std::nullopt
के तौर पर सेट करना). हालांकि, Java क्लाइंट इसे शून्य के तौर पर नहीं पढ़ सकता.
पार्स किए जा सकने वाले स्ट्रक्चर्ड सामान
1. कब इस्तेमाल करें
स्ट्रक्चर्ड पार्सलबल का इस्तेमाल तब करें, जब आपको एक से ज़्यादा तरह का डेटा भेजना हो.
इसके अलावा, जब आपके पास एक ही डेटा टाइप हो, लेकिन आपको आने वाले समय में उसे बड़ा करना हो. उदाहरण के लिए, String username
का इस्तेमाल न करें. ऐसे पार्सल का इस्तेमाल करें जिसे बड़ा किया जा सकता हो. जैसे:
parcelable User {
String username;
}
आने वाले समय में, इसे इस तरह बढ़ाया जा सकता है:
parcelable User {
String username;
int id;
}
2. डिफ़ॉल्ट वैल्यू साफ़ तौर पर दें
[-Wexplicit-default, -Wenum-explicit-default] फ़ील्ड के लिए साफ़ तौर पर डिफ़ॉल्ट वैल्यू दें.
पार्सल नहीं किए जा सकने वाले स्ट्रक्चर्ड डेटा
1. कब इस्तेमाल करें
नॉन-स्ट्रक्चर्ड पार्सल, Java में @JavaOnlyStableParcelable
के साथ और एनडीके बैकएंड में @NdkOnlyStableParcelable
के साथ उपलब्ध हैं. आम तौर पर, ये पुराने और मौजूदा पार्स किए जा सकने वाले ऐसे पार्स किए जा सकते हैं
जिन्हें व्यवस्थित नहीं किया जा सकता.
कॉन्स्टेंट और ईनम
1. बिटफ़ील्ड में, कॉन्स्टेंट फ़ील्ड का इस्तेमाल किया जाना चाहिए
बिटफ़ील्ड में कॉन्सटैंट फ़ील्ड का इस्तेमाल किया जाना चाहिए (उदाहरण के लिए, किसी इंटरफ़ेस में const int FOO = 3;
).
2. एनोटेशन, क्लोज़्ड सेट होने चाहिए.
एनोटेशन, क्लोज़्ड सेट होने चाहिए. ध्यान दें: सिर्फ़ इंटरफ़ेस का मालिक ही, सूची के एलिमेंट जोड़ सकता है. अगर वेंडर या OEM को इन फ़ील्ड का दायरा बढ़ाना है, तो दूसरे तरीके की ज़रूरत होगी. जब भी हो सके, तो वेंडर की अपस्ट्रीम करने की सुविधा को प्राथमिकता दी जानी चाहिए. हालांकि, कुछ मामलों में, कस्टम वेंडर वैल्यू को अनुमति दी जा सकती है. हालांकि, वेंडर के पास इसकी वैल्यू को बदलने का कोई तरीका होना चाहिए. शायद यह तरीका AIDL में ही मौजूद हो. वेंडर वैल्यू एक-दूसरे से मेल नहीं खानी चाहिए और इन्हें तीसरे पक्ष के ऐप्लिकेशन को नहीं दिखाया जाना चाहिए.
3. "NUM_ELEMENTS" जैसी वैल्यू का इस्तेमाल न करें
वैल्यू की सूची के वर्शन होते हैं. इसलिए, ऐसी वैल्यू का इस्तेमाल नहीं किया जाना चाहिए जिनसे यह पता चलता हो कि कितनी वैल्यू मौजूद हैं. C++ में, enum_range<>
का इस्तेमाल करके इस समस्या को हल किया जा सकता है. Rust के लिए, enum_values()
का इस्तेमाल करें. Java में, अभी तक कोई समाधान नहीं है.
इसका सुझाव नहीं दिया जाता: नंबर वाली वैल्यू का इस्तेमाल करना
@Backing(type="int")
enum FruitType {
APPLE = 0,
BANANA = 1,
MANGO = 2,
NUM_TYPES, // BAD
}
4. ज़रूरत से ज़्यादा प्रीफ़िक्स और सफ़िक्स इस्तेमाल न करें
[-Wredundant-name] कॉन्स्टेंट और एनोमेरेटर में, ग़ैर-ज़रूरी या बार-बार इस्तेमाल होने वाले प्रीफ़िक्स और सफ़िक्स से बचें.
इसका सुझाव नहीं दिया जाता: ग़ैर-ज़रूरी प्रीफ़िक्स का इस्तेमाल करना
enum MyStatus {
STATUS_GOOD,
STATUS_BAD // BAD
}
सुझाव: ईनम को सीधे तौर पर नाम देना
enum MyStatus {
GOOD,
BAD
}
FileDescriptor
[-Wfile-descriptor] FileDescriptor
को आर्ग्युमेंट के तौर पर इस्तेमाल करने या किसी AIDL इंटरफ़ेस के तरीके की रिटर्न वैल्यू के तौर पर इस्तेमाल करने का सुझाव नहीं दिया जाता. खास तौर पर, जब एआईडीएल को Java में लागू किया जाता है, तो इससे फ़ाइल डिस्क्रिप्टर लीक हो सकता है. हालांकि, ऐसा तब ही होगा, जब इसे ध्यान से मैनेज न किया जाए. इसका मतलब है कि अगर FileDescriptor
को स्वीकार किया जाता है, तो इसका इस्तेमाल न किए जाने पर, आपको इसे मैन्युअल तरीके से बंद करना होगा.
नेटिव बैकएंड के लिए, आप सुरक्षित हैं, क्योंकि FileDescriptor
, unique_fd
पर मैप होता है, जो अपने-आप बंद हो जाता है. हालांकि, बैकएंड के लिए किसी भी भाषा का इस्तेमाल किया जा सकता है, लेकिन FileDescriptor
का इस्तेमाल बिलकुल न करें. ऐसा करने से, आने वाले समय में बैकएंड की भाषा बदलने में समस्या आ सकती है.
इसके बजाय, ParcelFileDescriptor
का इस्तेमाल करें, जो अपने-आप बंद हो जाता है.
वैरिएबल की इकाइयां
पक्का करें कि वैरिएबल की इकाइयां नाम में शामिल हों, ताकि दस्तावेज़ों का रेफ़रंस दिए बिना ही उनकी इकाइयों को अच्छी तरह से समझा और परिभाषित किया जा सके
उदाहरण
long duration; // Bad
long durationNsec; // Good
long durationNanos; // Also good
double energy; // Bad
double energyMilliJoules; // Good
int frequency; // Bad
int frequencyHz; // Good
टाइमस्टैंप में उनका रेफ़रंस होना चाहिए
टाइमस्टैंप (वास्तव में, सभी यूनिट!) में उनकी यूनिट और रेफ़रंस पॉइंट साफ़ तौर पर दिखने चाहिए.
उदाहरण
/**
* 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;