यहां बताए गए सबसे सही तरीके, AIDL इंटरफ़ेस को असरदार तरीके से और इंटरफ़ेस की फ़्लेक्सिबिलिटी को ध्यान में रखते हुए डेवलप करने में मदद करते हैं. खास तौर पर, तब जब AIDL का इस्तेमाल, बैकवर्ड-कम्पैटिबल और स्थिर एपीआई तय करने के लिए किया जाता है.
AIDL का इस्तेमाल, एपीआई तय करने के लिए किया जा सकता है. ऐसा तब किया जाता है, जब ऐप्लिकेशन को बैकग्राउंड प्रोसेस में एक-दूसरे के साथ इंटरफ़ेस करना हो या सिस्टम के साथ इंटरफ़ेस करना हो.
एचएएल इंटरफ़ेस के लिए, @VintfStability के साथ स्थिर AIDL का इस्तेमाल किया जाता है. इससे क्लाइंट और सर्वर को अलग-अलग अपडेट किया जा सकता है. इसके लिए, बैकवर्ड-कम्पैटिबिलिटी और स्ट्रक्चर्ड डेटा की ज़रूरत होती है.
AIDL की मदद से, ऐप्लिकेशन में प्रोग्रामिंग इंटरफ़ेस डेवलप करने के बारे में ज़्यादा जानने के लिए, Android इंटरफ़ेस डेफ़िनिशन लैंग्वेज (AIDL) लेख देखें. व्यवहार में AIDL के उदाहरण देखने के लिए, एचएएल के लिए AIDL और स्थिर AIDL लेख देखें.
वर्शन
AIDL एपीआई के बैकवर्ड-कम्पैटिबल हर स्नैपशॉट के लिए एक वर्शन होता है.
स्नैपशॉट लेने के लिए, m <module-name>-freeze-api चलाएं. जब भी एपीआई का कोई क्लाइंट या सर्वर रिलीज़ किया जाता है (उदाहरण के लिए, मेनलाइन ट्रेन में), तब आपको एक स्नैपशॉट लेना होता है और एक नया वर्शन बनाना होता है. सिस्टम-टू-वेंडर एपीआई के लिए, यह हर साल प्लैटफ़ॉर्म में होने वाले बदलाव के साथ होना चाहिए.
जब किसी इंटरफ़ेस को फ़्रीज़ किया जाता है (वर्शन वाली aidl_api डायरेक्ट्री में सेव किया जाता है), तो उसमें कभी भी बदलाव नहीं किया जाना चाहिए. सिर्फ़ current डायरेक्ट्री में बदलाव किया जा सकता है. किसी इंटरफ़ेस के आखिर में, तरीके, पार्सल करने लायक ऑब्जेक्ट के आखिर में फ़ील्ड, enum में एन्यूमरेटर, और यूनियन में सदस्य जोड़े जा सकते हैं. ऐसा करने से कोई समस्या नहीं होती.
पुराने सर्वर पर नए तरीके कॉल करने वाले क्लाइंट को UNKNOWN_TRANSACTION गड़बड़ी मिलती है. क्लाइंट को इसे आसानी से हैंडल करना चाहिए.
अनुमति वाले बदलावों के टाइप के बारे में ज़्यादा जानकारी और अन्य जानकारी के लिए, इंटरफ़ेस के वर्शन लेख देखें.
बिल्ड डिपेंडेंसी
Android मॉड्यूल, aidl_interface से जनरेट की गई लाइब्रेरी के एक से ज़्यादा और अलग-अलग वर्शन पर निर्भर नहीं हो सकते. लाइब्रेरी के अलग-अलग वर्शन, एक ही नेमस्पेस में एक ही तरह के टाइप तय करते हैं. Android का aidl बिल्ड सिस्टम, इस समस्या की पहचान करता है और डिपेंडेंसी ग्राफ़ में से हर एक के साथ गड़बड़ी दिखाता है. ये ग्राफ़, लाइब्रेरी के मेल न खाने वाले वर्शन में खत्म होते हैं.
जब किसी मॉड्यूल में, अपनी डिपेंडेंसी वाली कई डिपेंडेंसी शामिल होती हैं, तो ऐसे में किसी सामान्य इंटरफ़ेस के एक वर्शन को अपडेट करना मुश्किल हो सकता है.
डेवलपर, शेयर किए गए इंटरफ़ेस की डिपेंडेंसी को अन्य इंटरफ़ेस पर दिखाने के लिए, aidl_interface_defaults का इस्तेमाल कर सकते हैं. इससे, उन सभी को अलग-अलग अपडेट करने की ज़रूरत नहीं होती.
जनरेट की गई लाइब्रेरी पर डिपेंडेंसी को व्यवस्थित करने के लिए, हम *_defaults मॉड्यूल (जैसे, rust_defaults, cc_defaults, java_defaults) का इस्तेमाल करने का सुझाव देते हैं. इंटरफ़ेस के latest वर्शन के साथ-साथ, पुराने वर्शन के लिए भी डिफ़ॉल्ट सेटिंग होना आम बात है. ऐसा तब होता है, जब उनका इस्तेमाल अब भी किया जा रहा हो.
डेवलपर, शेयर किए गए इंटरफ़ेस की डिपेंडेंसी को अन्य इंटरफ़ेस पर दिखाने के लिए, aidl_interface_defaults का इस्तेमाल कर सकते हैं. इससे, उन सभी को अलग-अलग अपडेट करने की ज़रूरत नहीं होती.
एपीआई डिज़ाइन के दिशा-निर्देश
सामान्य
1. हर चीज़ के बारे में दस्तावेज़ तैयार करना
- हर तरीके के लिए, उसके सिमैंटिक्स, आर्ग्युमेंट, बिल्ट-इन अपवादों का इस्तेमाल, सेवा से जुड़े खास अपवाद, और रिटर्न वैल्यू के बारे में दस्तावेज़ तैयार करें.
- हर इंटरफ़ेस के लिए, उसके सिमैंटिक्स के बारे में दस्तावेज़ तैयार करें.
- एनम और कॉन्स्टेंट के सिमैंटिक मतलब के बारे में दस्तावेज़ तैयार करें.
- ऐसी हर चीज़ के बारे में दस्तावेज़ तैयार करें जो लागू करने वाले व्यक्ति के लिए साफ़ न हो.
- ज़रूरत पड़ने पर, उदाहरण दें.
2. केसिंग
टाइप के लिए अपर कैमल केसिंग और तरीकों, फ़ील्ड, और आर्ग्युमेंट के लिए लोअर कैमल केसिंग का इस्तेमाल करें. उदाहरण के लिए, पार्सल करने लायक टाइप के लिए MyParcelable और आर्ग्युमेंट के लिए anArgument
का इस्तेमाल करें. ऐक्रनिम के लिए, ऐक्रनिम को एक शब्द मानें (NFC -> Nfc).
[-Wconst-name] एनम वैल्यू और कॉन्स्टेंट, ENUM_VALUE और CONSTANT_NAME होने चाहिए
3. ग्लोबल जानकारी की ज़रूरत से बचना
एपीआई को यह नहीं मानना चाहिए कि डेवलपर के पास पूरे कोडबेस या किसी खास डोमेन की विशेषज्ञता की ग्लोबल जानकारी है. डोमेन से जुड़े आइडेंटिफ़ायर (जैसे, डिवाइस के नाम, आईडी या हैंडल) के साथ काम करते समय:
- साफ़ तौर पर बताएं और दस्तावेज़ तैयार करें कि ये आइडेंटिफ़ायर कहां से आते हैं और इनका फ़ॉर्मैट क्या है. ऐसा तब करें, जब इंटरफ़ेस के दोनों पक्षों के लिए इनकी जानकारी होना ज़रूरी हो.
- इसके अलावा, इंटरफ़ेस से जुड़े आइडेंटिफ़ायर (जैसे, बाइंडर ऑब्जेक्ट या कस्टम टोकन) का इस्तेमाल करें. साथ ही, एक पक्ष को, असली वैल्यू के साथ मैपिंग मैनेज करने दें. इससे टकराव कम होते हैं और उपयोगकर्ताओं को, अपने दायरे से बाहर की जानकारी को समझने की ज़रूरत नहीं पड़ती.
4. सभी डेटा स्ट्रक्चर्ड और बैकवर्ड-कम्पैटिबल होते हैं
string, byte[], और शेयर की गई मेमोरी जैसे अनस्ट्रक्चर्ड डेटा का कॉन्टेंट, स्थिर फ़ॉर्मैट में होना चाहिए. इसके अलावा, इंटरफ़ेस के एक पक्ष के लिए यह अपारदर्शी होना चाहिए.
उदाहरण के लिए, किसी नतीजे के लिए गड़बड़ी के मैसेज के तौर पर इस्तेमाल किया गया स्ट्रिंग आर्ग्युमेंट, डीबग करने के लिए रिसीव और लॉग किया जा सकता है. हालांकि, इसे पार्स और इंटरप्रेट नहीं किया जाना चाहिए, क्योंकि हो सकता है कि इसका फ़ॉर्मैट और कॉन्टेंट बैकवर्ड-कम्पैटिबल न हो. अगर इंटरफ़ेस के दूसरे पक्ष को रन टाइम पर यह जानना है कि गड़बड़ी क्या है, तो एनम, कॉन्स्टेंट या ServiceSpecificException का इस्तेमाल करें.
इसी तरह, ऑब्जेक्ट को byte[] या शेयर की गई मेमोरी में तब तक सीरियलाइज़ न करें, जब तक वे स्थिर और बैकवर्ड-कम्पैटिबल न हों. कुछ मामलों में, शेयर की गई मेमोरी और फ़ास्ट मैसेज क्यू में, पार्सल करने लायक ऑब्जेक्ट और यूनियन शेयर करने के लिए, @FixedSize एनोटेशन का इस्तेमाल किया जा सकता है.
इंटरफ़ेस
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. स्टेटस कोड दिखाने से बचना
तरीकों को रिटर्न वैल्यू के तौर पर स्टेटस कोड दिखाने से बचना चाहिए, क्योंकि सभी AIDL तरीकों में, स्टेटस रिटर्न कोड पहले से मौजूद होता है. ServiceSpecificException या EX_SERVICE_SPECIFIC देखें. आम तौर पर, इन वैल्यू को AIDL इंटरफ़ेस में कॉन्स्टेंट के तौर पर तय किया जाता है. अगर किसी गड़बड़ी के साथ, कस्टम डिले या गड़बड़ी का यूनीक डेटा चाहिए, तो कस्टम रिस्पॉन्स ऑब्जेक्ट को गड़बड़ी के तौर पर दिखाया जाना चाहिए. ज़्यादा जानकारी के लिए, गड़बड़ी को हैंडल करना लेख देखें.
5. आउटपुट पैरामीटर के तौर पर ऐरे का इस्तेमाल करना नुकसानदेह हो सकता है
[-Wout-array] जिन तरीकों में आउटपुट पैरामीटर के तौर पर ऐरे का इस्तेमाल किया जाता है वे आम तौर पर सही नहीं होते. जैसे, void foo(out String[] ret). ऐसा इसलिए, क्योंकि Java में क्लाइंट को आउटपुट ऐरे का साइज़ तय करना और उसे असाइन करना होता है. इसलिए, सर्वर, ऐरे आउटपुट का साइज़ नहीं चुन सकता. यह अवांछित व्यवहार, 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 क्लाइंट इसे शून्य के तौर पर नहीं पढ़ सकता.
8. अनुरोधों और जवाबों के लिए यूनीक वैल्यू का इस्तेमाल करना
ज़रूरी सभी पैरामीटर को, एक ही इनपुट parcelable में ग्रुप करें.
हर इंटरफ़ेस तरीके के लिए, प्रिमिटिव पास करने के बजाय, अनुरोध और जवाब के लिए पार्सल करने लायक ऑब्जेक्ट बनाएं. उदाहरण के लिए, अलग-अलग वैरिएबल पास करने के बजाय, ComputeResponse compute(in ComputeRequest request) का इस्तेमाल करें. इससे फ़ंक्शन सिग्नेचर में बदलाव किए बिना, बाद में नए आर्ग्युमेंट जोड़े जा सकते हैं. इस पैटर्न का इस्तेमाल करने का सुझाव तब दिया जाता है, जब आने वाले समय में और पैरामीटर जोड़े जाने की उम्मीद हो या किसी तरीके में पहले से ही चार से ज़्यादा पैरामीटर मौजूद हों.
जिन तरीकों के लिए अतिरिक्त इनपुट या आउटपुट की ज़रूरत नहीं होती उन्हें इस सुझाव से कोई फ़ायदा नहीं मिलेगा. हर मामले के बारे में साफ़ तौर पर सोचने और आने वाले समय में होने वाले बदलावों के लिए फ़्लेक्सिबल रहने से, बंद किए गए तरीकों की संख्या कम हो सकती है. साथ ही, बैकवर्ड-कम्पैटिबल कोड की जटिलता भी कम हो सकती है.
अगर कोई तरीका इस पैटर्न का इस्तेमाल करके नहीं बनाया गया है, तो अनुरोध और जवाब के लिए पार्सल करने लायक ऑब्जेक्ट वाला नया तरीका बनाकर और पुराने तरीके को बंद करके, इस पैटर्न पर स्विच किया जा सकता है. उदाहरण के लिए:
void foo(int a, int b, int c); // original version, but deprecated in favor of the next version
void fooV2(in MyArg arg); // new version having int a, b, c, and d.
स्ट्रक्चर्ड पार्सल करने लायक ऑब्जेक्ट
1. कब इस्तेमाल करें
स्ट्रक्चर्ड पार्सल करने लायक ऑब्जेक्ट का इस्तेमाल तब करें, जब आपको एक से ज़्यादा डेटा टाइप भेजने हों.
या, तब जब आपके पास एक ही डेटा टाइप हो, लेकिन आपको उम्मीद हो कि आने वाले समय में आपको इसे बढ़ाना होगा. उदाहरण के लिए, String username का इस्तेमाल न करें. पार्सल करने लायक ऑब्जेक्ट का इस्तेमाल करें, जिसे बढ़ाया जा सकता है. जैसे, यह:
parcelable User {
String username;
}
ताकि आने वाले समय में, इसे इस तरह बढ़ाया जा सके:
parcelable User {
String username;
int id;
}
2. डिफ़ॉल्ट वैल्यू साफ़ तौर पर देना
[-Wexplicit-default, -Wenum-explicit-default] फ़ील्ड के लिए, साफ़ तौर पर डिफ़ॉल्ट वैल्यू दें. जब पार्सल करने लायक ऑब्जेक्ट में नए फ़ील्ड जोड़े जाते हैं, तो पुराने क्लाइंट और सर्वर उन्हें छोड़ देते हैं. हालांकि, नए क्लाइंट और सर्वर के लिए डिफ़ॉल्ट वैल्यू अपने-आप भर जाती हैं.
3. वेंडर एक्सटेंशन के लिए ParcelableHolder का इस्तेमाल करना
अगर आपको AOSP parcelable तय करना है जिसे डिवाइस लागू करने वाले लोगों को बढ़ाना है, तो अपने ऑब्जेक्ट में ParcelableHolder का कोई इंस्टेंस एम्बेड करें. यह मर्ज के टकराव पैदा किए बिना, एक्सटेंशन पॉइंट के तौर पर काम करता है. यह अटैच किए गए इंटरफ़ेस एक्सटेंशन की तरह है. हालांकि, इससे लागू करने वाले लोग, अपना इंटरफ़ेस और टाइप बनाए बिना, मौजूदा parcelable के साथ अपना मालिकाना हक वाला parcelable शामिल कर सकते हैं.
4. डेटा स्ट्रक्चर
- मैप दिखाने के लिए, पार्सल करने लायक ऑब्जेक्ट के ऐरे या
Listका इस्तेमाल करें, क्योंकि AIDL,Mapटाइप को मूल रूप से सपोर्ट नहीं करता. ये टाइप, सभी नेटिव बैकएंड में सुरक्षित तरीके से ट्रांसलेट होते हैं. उदाहरण के लिए,FeatureToScoreEntry[]. - आने वाले समय में, पैरलल ऐरे की ज़रूरत से बचने के लिए, बार-बार इस्तेमाल होने वाले फ़ील्ड के लिए, प्रिमिटिव के ऐरे के बजाय,
parcelableऑब्जेक्ट के ऐरे का इस्तेमाल करें. - आईपीसी पर सीरियलाइज़ की गई स्ट्रिंग या JSON के बजाय, मज़बूती से टाइप किए गए
parcelableऑब्जेक्ट का इस्तेमाल करें. - आने वाले समय में, विस्तार की अनुमति देने के लिए, स्थितियों के लिए बूलियन के बजाय एनम का इस्तेमाल करें. बिटमास्क के लिए, कुछ बैकएंड में मुश्किल कास्टिंग से बचने के लिए,
enumटाइप के बजायconst intका इस्तेमाल करें.
नॉनस्ट्रक्चर्ड पार्सल करने लायक ऑब्जेक्ट
1. कब इस्तेमाल करें
नॉनस्ट्रक्चर्ड पार्सल करने लायक ऑब्जेक्ट, Java में @JavaOnlyStableParcelable के साथ और NDK बैकएंड में @NdkOnlyStableParcelable के साथ उपलब्ध हैं. आम तौर पर, ये पुराने और मौजूदा पार्सल करने लायक ऑब्जेक्ट होते हैं जिन्हें स्ट्रक्चर्ड नहीं किया जा सकता.
कॉन्स्टेंट और एनम
1. बिटफ़ील्ड में कॉन्स्टेंट फ़ील्ड का इस्तेमाल किया जाना चाहिए
बिटफ़ील्ड में कॉन्स्टेंट फ़ील्ड का इस्तेमाल किया जाना चाहिए. उदाहरण के लिए, किसी इंटरफ़ेस में const int FOO = 3;.
2. एनम, क्लोज़्ड सेट होने चाहिए.
एनम, क्लोज़्ड सेट होने चाहिए. ध्यान दें: सिर्फ़ इंटरफ़ेस का मालिक, एनम एलिमेंट जोड़ सकता है. अगर वेंडर या ओईएम को इन फ़ील्ड को बढ़ाना है, तो किसी दूसरे तरीके की ज़रूरत होती है. जब भी हो सके, वेंडर की फ़ंक्शनैलिटी को अपस्ट्रीम करने को प्राथमिकता दी जानी चाहिए. हालांकि, कुछ मामलों में, वेंडर की कस्टम वैल्यू की अनुमति दी जा सकती है. हालांकि, वेंडर के पास इसे वर्शन करने का कोई तरीका होना चाहिए. शायद, 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] AIDL इंटरफ़ेस के किसी तरीके के आर्ग्युमेंट या रिटर्न वैल्यू के तौर पर, 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;
कॉन्करेंसी और एसिंक्रोनस कार्रवाइयां
ब्लॉक होने से बचने के लिए, लंबे समय तक चलने वाली कार्रवाइयों को एसिंक्रोनस (oneway) इंटरफ़ेस से हैंडल करें.
अगर कोई सेवा अपने क्लाइंट पर भरोसा नहीं करती है, तो उसे क्लाइंट से मिलने वाले सभी कॉलबैक, oneway इंटरफ़ेस होने चाहिए. इससे क्लाइंट, सेवा को हमेशा के लिए ब्लॉक नहीं कर पाएंगे.
एसिंक्रोनस एपीआई को इस तरह से स्ट्रक्चर करें कि उसमें फ़ॉरवर्ड कॉल, इनपुट आर्ग्युमेंट, और नतीजे पाने के लिए कॉलबैक इंटरफ़ेस शामिल हो. आर्ग्युमेंट के लिए सुझाव पाने के लिए, अनुरोधों और जवाबों के लिए यूनीक वैल्यू का इस्तेमाल करना लेख देखें.