AIDL API নির্দেশিকা

এখানে বর্ণিত সর্বোত্তম অনুশীলনগুলি কার্যকরভাবে এবং ইন্টারফেসের নমনীয়তার প্রতি মনোযোগ দিয়ে AIDL ইন্টারফেস তৈরি করার জন্য একটি নির্দেশিকা হিসাবে কাজ করে, বিশেষ করে যখন একটি স্থিতিশীল, পশ্চাৎ-সামঞ্জস্যপূর্ণ API সংজ্ঞায়িত করতে AIDL ব্যবহৃত হয়।

যখন অ্যাপগুলোকে ব্যাকগ্রাউন্ড প্রসেসে একে অপরের সাথে অথবা সিস্টেমের সাথে ইন্টারফেস করার প্রয়োজন হয়, তখন একটি API সংজ্ঞায়িত করতে AIDL ব্যবহার করা যেতে পারে।

@VintfStability সহ স্থিতিশীল AIDL, HAL ইন্টারফেসের জন্য ব্যবহৃত হয় এবং ক্লায়েন্ট ও সার্ভারকে স্বাধীনভাবে আপডেট করার সুযোগ দেয়। এর জন্য পশ্চাৎ সামঞ্জস্যতা (backward compatibility) এবং কাঠামোগত ডেটা (structured data) প্রয়োজন।

AIDL ব্যবহার করে অ্যাপে প্রোগ্রামিং ইন্টারফেস তৈরি করার বিষয়ে আরও তথ্যের জন্য, Android Interface Definition Language (AIDL) দেখুন। বাস্তবে AIDL-এর উদাহরণের জন্য, AIDL for HALs এবং Stable AIDL দেখুন।

সংস্করণ

একটি AIDL API-এর প্রতিটি ব্যাকওয়ার্ড-কম্প্যাটিবল স্ন্যাপশট একটি ভার্সনের সাথে সঙ্গতিপূর্ণ। একটি স্ন্যাপশট নিতে, m <module-name>-freeze-api চালান। যখনই API-এর কোনো ক্লায়েন্ট বা সার্ভার রিলিজ করা হয় (উদাহরণস্বরূপ, একটি মেইনলাইন ট্রেনে), আপনাকে একটি স্ন্যাপশট নিতে হবে এবং একটি নতুন ভার্সন তৈরি করতে হবে। সিস্টেম-টু-ভেন্ডর API-গুলোর ক্ষেত্রে, এটি বার্ষিক প্ল্যাটফর্ম রিভিশনের সাথে হওয়া উচিত।

যখন কোনো ইন্টারফেস ফ্রিজ করা হয় (ভার্সনযুক্ত aidl_api ডিরেক্টরিতে সেভ করা হয়), তখন তা কখনোই পরিবর্তন করা যাবে না। আপনি শুধুমাত্র current ডিরেক্টরিটি এডিট করতে পারবেন। আপনি নিরাপদে একটি ইন্টারফেসের শেষে মেথড, একটি পার্সেলএবল-এর শেষে ফিল্ড, একটি এনাম-এ এনুমেটর এবং একটি ইউনিয়ন-এ মেম্বার যোগ করতে পারেন।

পুরোনো সার্ভারে নতুন মেথড কল করলে ক্লায়েন্টরা একটি UNKNOWN_TRANSACTION এরর পায়, যা ক্লায়েন্টের পক্ষ থেকে সাবলীলভাবে সামলানো উচিত।

কী ধরনের পরিবর্তন অনুমোদিত, সে সম্পর্কে আরও বিস্তারিত জানতে ভার্সনিং ইন্টারফেস দেখুন।

বিল্ড নির্ভরতা

অ্যান্ড্রয়েড মডিউলগুলো একটি aidl_interface থেকে তৈরি হওয়া লাইব্রেরির একাধিক ভিন্ন সংস্করণের উপর নির্ভর করতে পারে না। লাইব্রেরির এই ভিন্ন সংস্করণগুলো একই নেমস্পেসের মধ্যে একই টাইপ সংজ্ঞায়িত করে। অ্যান্ড্রয়েডের aidl বিল্ড সিস্টেম এই সমস্যাটি শনাক্ত করে এবং লাইব্রেরির অমিল সংস্করণগুলোতে শেষ হওয়া প্রতিটি ডিপেন্ডেন্সি গ্রাফের জন্য একটি ত্রুটি দেখায়।

যখন কোনো মডিউলে অনেকগুলো ডিপেন্ডেন্সি থাকে এবং সেগুলোরও নিজস্ব ডিপেন্ডেন্সি থাকে, তখন একটি সাধারণ ইন্টারফেসের যেকোনো একটি ভার্সন আপডেট করা কঠিন হয়ে পড়তে পারে।

ডেভেলপাররা একটি শেয়ার্ড ইন্টারফেসের অন্যান্য ইন্টারফেসের উপর নির্ভরতা ঘোষণা করার জন্য aidl_interface_defaults ব্যবহার করতে পারেন, যাতে সেগুলোকে আলাদাভাবে আপডেট করার প্রয়োজন না হয়।

জেনারেট করা লাইব্রেরিগুলোর ডিপেন্ডেন্সি গুছিয়ে রাখার জন্য আমরা *_defaults মডিউল (যেমন rust_defaults , cc_defaults , java_defaults ) ব্যবহার করার পরামর্শ দিই। ইন্টারফেসগুলোর latest সংস্করণের জন্য একটি ডিফল্ট থাকার পাশাপাশি, পূর্ববর্তী সংস্করণগুলো এখনও ব্যবহৃত হলে সেগুলোর জন্যও ডিফল্ট রাখা একটি সাধারণ রীতি।

ডেভেলপাররা একটি শেয়ার্ড ইন্টারফেসের অন্যান্য ইন্টারফেসের উপর নির্ভরতা ঘোষণা করার জন্য aidl_interface_defaults ব্যবহার করতে পারেন, যাতে সেগুলোকে আলাদাভাবে আপডেট করার প্রয়োজন না হয়।

এপিআই ডিজাইন নির্দেশিকা

সাধারণ

১. সবকিছু নথিভুক্ত করুন

  • প্রতিটি মেথডের অর্থ, আর্গুমেন্ট, বিল্ট-ইন এক্সেপশনের ব্যবহার, সার্ভিস-নির্দিষ্ট এক্সেপশন এবং রিটার্ন ভ্যালু নথিভুক্ত করুন।
  • প্রতিটি ইন্টারফেসের অর্থ ও তাৎপর্য নথিভুক্ত করুন।
  • এনাম এবং কনস্ট্যান্টের শব্দার্থগত তাৎপর্য নথিভুক্ত করুন।
  • বাস্তবায়নকারীর কাছে যা কিছু অস্পষ্ট থাকতে পারে, তা নথিভুক্ত করুন।
  • প্রাসঙ্গিক ক্ষেত্রে উদাহরণ দিন।

২. কেসিং

টাইপের জন্য আপার ক্যামেল কেসিং এবং মেথড, ফিল্ড ও আর্গুমেন্টের জন্য লোয়ার ক্যামেল কেসিং ব্যবহার করুন। উদাহরণস্বরূপ, পার্সেলযোগ্য টাইপের জন্য MyParcelable এবং আর্গুমেন্টের জন্য anArgument । সংক্ষিপ্ত রূপের ক্ষেত্রে, সংক্ষিপ্ত রূপটিকে একটি শব্দ হিসেবে বিবেচনা করুন ( NFC -> Nfc )।

[-Wconst-name] Enum ভ্যালু এবং কনস্ট্যান্ট অবশ্যই ENUM_VALUE এবং CONSTANT_NAME হতে হবে।

৩. বৈশ্বিক জ্ঞানের প্রয়োজনীয়তা পরিহার করুন

এপিআই-এর ক্ষেত্রে এটা ধরে নেওয়া উচিত নয় যে ডেভেলপারদের সম্পূর্ণ কোডবেস সম্পর্কে সার্বিক জ্ঞান অথবা কোনো নির্দিষ্ট ডোমেইনে দক্ষতা রয়েছে। ডোমেইন-নির্দিষ্ট আইডেন্টিফায়ার (যেমন ডিভাইসের নাম, আইডি, বা হ্যান্ডেল) ব্যবহারের ক্ষেত্রে:

  • যদি ইন্টারফেসের উভয় পক্ষের জন্য এই আইডেন্টিফায়ারগুলো জানা গুরুত্বপূর্ণ হয়, তাহলে সেগুলোর উৎস এবং ফরম্যাট স্পষ্টভাবে উল্লেখ করুন ও নথিভুক্ত করুন।
  • বিকল্পভাবে, ইন্টারফেস-নির্দিষ্ট আইডেন্টিফায়ার (যেমন বাইন্ডার অবজেক্ট বা কাস্টম টোকেন) ব্যবহার করুন এবং এক পক্ষকে অন্তর্নিহিত মানগুলির সাথে ম্যাপিংয়ের কাজটি পরিচালনা করতে দিন। এটি সংঘর্ষ কমায় এবং ব্যবহারকারীদের তাদের আওতার বাইরের বাস্তবায়নের খুঁটিনাটি বোঝার প্রয়োজনীয়তা এড়ায়।

৪. সমস্ত ডেটা সুসংগঠিত এবং পূর্ববর্তী সংস্করণের সাথে সামঞ্জস্যপূর্ণ।

string , byte[] এবং শেয়ার্ড মেমরির মতো অসংগঠিত ডেটার বিষয়বস্তুর একটি স্থিতিশীল ফরম্যাট থাকতে হবে, নতুবা তা ইন্টারফেসের এক পক্ষের কাছে অস্বচ্ছ হতে হবে।

উদাহরণস্বরূপ, কোনো ফলাফলের জন্য ত্রুটি বার্তা হিসেবে ব্যবহৃত একটি স্ট্রিং আর্গুমেন্ট ডিবাগিংয়ের জন্য গ্রহণ ও লগ করা যেতে পারে, কিন্তু এটিকে পার্স বা ব্যাখ্যা করা উচিত নয়, কারণ এর ফরম্যাট এবং বিষয়বস্তু পূর্ববর্তী সংস্করণের সাথে সামঞ্জস্যপূর্ণ নাও হতে পারে। যদি ইন্টারফেসের অপর প্রান্তের রান টাইমে ত্রুটিটি কী তা জানার প্রয়োজন হয়, তবে একটি enum, constant, বা ServiceSpecificException ব্যবহার করুন।

একইভাবে, অবজেক্টগুলোকে byte[] বা শেয়ার্ড মেমরিতে সিরিয়ালাইজ করবেন না, যদি না সেগুলো স্টেবল এবং ব্যাকওয়ার্ড কম্প্যাটিবল হয়। কিছু ক্ষেত্রে, শেয়ার্ড মেমরিতে পার্সেলএবল ও ইউনিয়ন শেয়ার করার জন্য এবং ফাস্ট মেসেজ কিউ-এর জন্য আপনি @FixedSize অ্যানোটেশনটি ব্যবহার করতে পারেন।

ইন্টারফেস

১. নামকরণ

[-Winterface-name] একটি ইন্টারফেসের নাম অবশ্যই I দিয়ে শুরু হতে হবে, যেমন IFoo

২. আইডি-ভিত্তিক 'অবজেক্ট' সহ বড় ইন্টারফেস পরিহার করুন।

যখন কোনো নির্দিষ্ট এপিআই (API) সম্পর্কিত অনেকগুলো কল থাকে, তখন সাব-ইন্টারফেস ব্যবহার করা শ্রেয়। এর ফলে নিম্নলিখিত সুবিধাগুলো পাওয়া যায়:

  • ক্লায়েন্ট বা সার্ভার কোড বোঝা সহজ করে তোলে
  • অবজেক্টের জীবনচক্রকে আরও সরল করে তোলে
  • বাইন্ডারগুলো জাল করা যায় না, এই সুবিধাটি গ্রহণ করে।

সুপারিশ করা হয় না: আইডি-ভিত্তিক অবজেক্ট সহ একটি একক, বৃহৎ ইন্টারফেস

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();
}

৩. একমুখী ও দ্বিমুখী পদ্ধতি মিশ্রিত করবেন না।

[-Wmixed-oneway] ওয়ান-ওয়ে এবং নন-ওয়ান-ওয়ে মেথড একসাথে ব্যবহার করবেন না, কারণ এটি ক্লায়েন্ট এবং সার্ভারের জন্য থ্রেডিং মডেল বোঝা জটিল করে তোলে। বিশেষ করে, কোনো নির্দিষ্ট ইন্টারফেসের ক্লায়েন্ট কোড পড়ার সময়, প্রতিটি মেথড ব্লক করবে কি না, তা আপনাকে খুঁজে দেখতে হবে।

৪. স্ট্যাটাস কোড ফেরত দেওয়া এড়িয়ে চলুন

মেথডগুলোর রিটার্ন ভ্যালু হিসেবে স্ট্যাটাস কোড ব্যবহার করা উচিত নয়, কারণ সমস্ত AIDL মেথডের একটি অন্তর্নিহিত স্ট্যাটাস রিটার্ন কোড থাকে। ServiceSpecificException বা EX_SERVICE_SPECIFIC দেখুন। প্রচলিত নিয়ম অনুযায়ী, এই ভ্যালুগুলো একটি AIDL ইন্টারফেসে কনস্ট্যান্ট হিসেবে সংজ্ঞায়িত করা হয়। যদি কোনো এররের পাশাপাশি একটি কাস্টম ডিলে বা স্বতন্ত্র এরর ডেটার প্রয়োজন হয়, তবেই কেবল একটি কাস্টম রেসপন্স অবজেক্ট এররটিকে উপস্থাপন করবে। আরও বিস্তারিত তথ্যের জন্য, এরর হ্যান্ডলিং দেখুন।

৫. আউটপুট প্যারামিটার হিসেবে অ্যারে ব্যবহার ক্ষতিকর বলে বিবেচিত হয়

[-Wout-array] void foo(out String[] ret) এর মতো অ্যারে আউটপুট প্যারামিটারযুক্ত মেথডগুলো সাধারণত অনুচিত, কারণ জাভাতে আউটপুট অ্যারের সাইজ ক্লায়েন্টকে ডিক্লেয়ার এবং অ্যালোকেট করতে হয়, ফলে সার্ভার আউটপুট অ্যারের সাইজ বেছে নিতে পারে না। এই অনাকাঙ্ক্ষিত আচরণটি ঘটে জাভাতে অ্যারের কার্যপ্রণালীর কারণে (এগুলো রিঅ্যালোকেট করা যায় না)। এর পরিবর্তে String[] foo() মতো এপিআই ব্যবহার করুন।

৬. ইনপুট/আউটপুট প্যারামিটার পরিহার করুন

[-Winout-parameter] এটি ক্লায়েন্টদের বিভ্রান্ত করতে পারে, কারণ in প্যারামিটারগুলোও out প্যারামিটারের মতো দেখতে লাগে।

৭. আউট এবং ইনআউট @nullable নন-অ্যারে প্যারামিটার পরিহার করুন।

[-Wout-nullable] যেহেতু জাভা ব্যাকএন্ড @nullable অ্যানোটেশনটি হ্যান্ডেল করে না, কিন্তু অন্যান্য ব্যাকএন্ড করে, তাই out/inout @nullable T বিভিন্ন ব্যাকএন্ডের মধ্যে অসামঞ্জস্যপূর্ণ আচরণের কারণ হতে পারে। উদাহরণস্বরূপ, নন-জাভা ব্যাকএন্ডগুলো একটি out @nullable প্যারামিটারকে null হিসেবে সেট করতে পারে (C++ এ, std::nullopt হিসেবে সেট করে), কিন্তু জাভা ক্লায়েন্ট এটিকে null হিসেবে পড়তে পারে না।

৮. স্বতন্ত্র অনুরোধ এবং প্রতিক্রিয়া ব্যবহার করুন

সমস্ত প্রয়োজনীয় প্যারামিটারকে একটিমাত্র ইনপুট 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.

কাঠামোগত পার্সেলযোগ্য

১. কখন ব্যবহার করতে হবে

যেখানে একাধিক ধরনের ডেটা পাঠানোর প্রয়োজন হয়, সেখানে স্ট্রাকচার্ড পার্সেল্যাবল ব্যবহার করুন।

অথবা, যখন আপনার একটিমাত্র ডেটা টাইপ থাকে কিন্তু আপনি আশা করেন যে ভবিষ্যতে এটিকে প্রসারিত করার প্রয়োজন হবে। উদাহরণস্বরূপ, String username ব্যবহার করবেন না। নিম্নলিখিতের মতো একটি এক্সটেন্ডেবল পার্সেলএবল (extendable parcelable) ব্যবহার করুন:

parcelable User {
    String username;
}

যাতে ভবিষ্যতে আপনি এটিকে নিম্নোক্তভাবে সম্প্রসারিত করতে পারেন:

parcelable User {
    String username;
    int id;
}

২. ডিফল্ট মান স্পষ্টভাবে প্রদান করুন

[-Wexplicit-default, -Wenum-explicit-default] ফিল্ডগুলির জন্য সুস্পষ্ট ডিফল্ট মান প্রদান করুন। যখন একটি পার্সেলযোগ্য ফাইলে নতুন ফিল্ড যোগ করা হয়, তখন পুরানো ক্লায়েন্ট এবং সার্ভারগুলি সেগুলি বাদ দেয়, কিন্তু নতুন ক্লায়েন্ট এবং সার্ভারগুলির জন্য ডিফল্ট মান স্বয়ংক্রিয়ভাবে পূরণ হয়ে যায়।

৩. ভেন্ডর এক্সটেনশনের জন্য ParcelableHolder ব্যবহার করুন

যদি আপনি এমন একটি AOSP parcelable সংজ্ঞায়িত করেন যা ডিভাইস ইমপ্লিমেন্টারদের এক্সটেন্ড করার প্রয়োজন হয়, তাহলে আপনার অবজেক্টের মধ্যে ParcelableHolder এর একটি ইনস্ট্যান্স এমবেড করুন। এটি মার্জ কনফ্লিক্ট তৈরি না করেই একটি এক্সটেনশন পয়েন্ট হিসেবে কাজ করে। এটি অ্যাটাচড ইন্টারফেস এক্সটেনশনের মতোই, তবে এটি ইমপ্লিমেন্টারদের নিজস্ব ইন্টারফেস এবং টাইপ তৈরি না করেই বিদ্যমান parcelable পাশাপাশি তাদের নিজস্ব parcelable অন্তর্ভুক্ত করার সুযোগ দেয়।

৪. ডেটা কাঠামো

  • ম্যাপ উপস্থাপনের জন্য পার্সেলযোগ্য ডেটার অ্যারে বা List ব্যবহার করুন, কারণ AIDL স্বাভাবিকভাবে Map টাইপ সমর্থন করে না যা সমস্ত নেটিভ ব্যাকএন্ডে নিরাপদে অনুবাদ করা যায় (উদাহরণস্বরূপ, FeatureToScoreEntry[] )।
  • ভবিষ্যতে প্যারালাল অ্যারের প্রয়োজনীয়তা এড়াতে, পুনরাবৃত্ত ফিল্ডগুলোর জন্য প্রিমিটিভের অ্যারের পরিবর্তে parcelable অবজেক্টের অ্যারে ব্যবহার করুন।
  • সিরিয়ালাইজড স্ট্রিং বা আইপিসি-এর মাধ্যমে JSON পাঠানোর পরিবর্তে স্ট্রংলি টাইপড parcelable অবজেক্ট ব্যবহার করুন।
  • ভবিষ্যৎ সম্প্রসারণের সুযোগ রাখতে স্টেট-এর জন্য বুলিয়ানের পরিবর্তে এনাম ব্যবহার করুন। কিছু ব্যাকএন্ডে ঝামেলাপূর্ণ কাস্টিং এড়াতে বিটমাস্কের জন্য enum টাইপের পরিবর্তে const int ব্যবহার করুন।

অসংগঠিত পার্সেলযোগ্য

১. কখন ব্যবহার করতে হবে

জাভাতে @JavaOnlyStableParcelable এবং NDK ব্যাকএন্ডে @NdkOnlyStableParcelable এর মাধ্যমে ননস্ট্রাকচার্ড পার্সেল্যাবল পাওয়া যায়। সাধারণত, এগুলো হলো পুরোনো এবং বিদ্যমান পার্সেল্যাবল, যেগুলোকে স্ট্রাকচার করা যায় না।

ধ্রুবক এবং এনাম

১. বিটফিল্ডে ধ্রুবক ফিল্ড ব্যবহার করা উচিত।

বিটফিল্ডে ধ্রুবক ফিল্ড ব্যবহার করা উচিত (উদাহরণস্বরূপ, একটি ইন্টারফেসে const int FOO = 3; )।

২. এনামগুলো বদ্ধ সেট হওয়া উচিত।

Enum-গুলো ক্লোজড সেট হওয়া উচিত। দ্রষ্টব্য: শুধুমাত্র ইন্টারফেসের মালিকই Enum এলিমেন্ট যোগ করতে পারেন। যদি ভেন্ডর বা OEM-দের এই ফিল্ডগুলো প্রসারিত করার প্রয়োজন হয়, তবে একটি বিকল্প পদ্ধতির প্রয়োজন হবে। যখনই সম্ভব, ভেন্ডরের কার্যকারিতা আপস্ট্রিম করাকে অগ্রাধিকার দেওয়া উচিত। তবে, কিছু ক্ষেত্রে, ভেন্ডরের নিজস্ব ভ্যালু ব্যবহারের অনুমতি দেওয়া যেতে পারে (যদিও, ভেন্ডরদের এটির ভার্সনিং করার জন্য একটি পদ্ধতি থাকা উচিত, সম্ভবত AIDL নিজেই, সেগুলোর মধ্যে যেন কোনো সংঘাত না হয়, এবং এই ভ্যালুগুলো যেন থার্ড-পার্টি অ্যাপের কাছে প্রকাশ না পায়)।

৩. "NUM_ELEMENTS"-এর মতো মান পরিহার করুন।

যেহেতু এনামগুলো ভার্সনযুক্ত, তাই কতগুলো ভ্যালু আছে তা নির্দেশ করে এমন মান পরিহার করা উচিত। C++ এ, enum_range<> ব্যবহার করে এর সমাধান করা যায়। রাস্টের জন্য, enum_values() ব্যবহার করুন। জাভাতে, এখনও কোনো সমাধান নেই।

সুপারিশ করা হয় না: সংখ্যাসূচক মান ব্যবহার করা।

@Backing(type="int")
enum FruitType {
    APPLE = 0,
    BANANA = 1,
    MANGO = 2,
    NUM_TYPES, // BAD
}

৪. অপ্রয়োজনীয় উপসর্গ ও প্রত্যয় পরিহার করুন

[-Wredundant-name] ধ্রুবক এবং গণনাকারীতে অপ্রয়োজনীয় বা পুনরাবৃত্তিমূলক উপসর্গ এবং প্রত্যয় পরিহার করুন।

সুপারিশ করা হয় না: একটি অপ্রয়োজনীয় উপসর্গ ব্যবহার করা।

enum MyStatus {
    STATUS_GOOD,
    STATUS_BAD // BAD
}

সুপারিশকৃত: সরাসরি এনামের নামকরণ করা

enum MyStatus {
    GOOD,
    BAD
}

ফাইলডেসক্রিপ্টর

[-Wfile-descriptor] কোনো AIDL ইন্টারফেস মেথডের আর্গুমেন্ট বা রিটার্ন ভ্যালু হিসেবে FileDescriptor এর ব্যবহারকে কঠোরভাবে নিরুৎসাহিত করা হয়। বিশেষ করে, যখন AIDL জাভাতে ইমপ্লিমেন্ট করা হয়, তখন সতর্কতার সাথে হ্যান্ডেল না করলে এটি ফাইল ডেসক্রিপ্টর লিকের কারণ হতে পারে। মূলত, আপনি যদি একটি 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 ইন্টারফেস হওয়া উচিত। এর ফলে ক্লায়েন্টরা সার্ভিসটিকে অনির্দিষ্টকালের জন্য ব্লক করতে পারে না।

একটি ফরওয়ার্ড কল, ইনপুট আর্গুমেন্ট এবং ফলাফল পাওয়ার জন্য একটি কলব্যাক ইন্টারফেস নিয়ে অ্যাসিঙ্ক্রোনাস এপিআই গঠন করুন। আর্গুমেন্টের সুপারিশের জন্য ‘Use unique requests and responses’ দেখুন।