অ্যান্ড্রয়েড অ্যাসিঙ্ক এবং ননব্লকিং API নির্দেশিকা

ননব্লকিং এপিআইগুলি কাজ হওয়ার জন্য অনুরোধ করে এবং তারপরে কলিং থ্রেডে নিয়ন্ত্রণ ফিরিয়ে দেয় যাতে অনুরোধ করা অপারেশন শেষ হওয়ার আগে এটি অন্য কাজ সম্পাদন করতে পারে। এই APIগুলি সেই ক্ষেত্রে উপযোগী যেখানে অনুরোধ করা কাজটি চলমান থাকতে পারে বা I/O বা IPC সমাপ্তির জন্য অপেক্ষা করতে হতে পারে, অত্যন্ত বিতর্কিত সিস্টেম সংস্থানগুলির উপলব্ধতা, বা কাজ এগিয়ে যাওয়ার আগে ব্যবহারকারীর ইনপুট প্রয়োজন হতে পারে। বিশেষ করে সু-পরিকল্পিত এপিআইগুলি প্রগতিতে থাকা ক্রিয়াকলাপটি বাতিল করার এবং মূল কলারের পক্ষে কাজ করা বন্ধ করার একটি উপায় প্রদান করে, যখন অপারেশনটির আর প্রয়োজন হয় না তখন সিস্টেমের স্বাস্থ্য এবং ব্যাটারির জীবন রক্ষা করে৷

অ্যাসিঙ্ক্রোনাস APIগুলি নন-ব্লকিং আচরণ অর্জনের একটি উপায়। Async APIগুলি কিছু ধরণের ধারাবাহিকতা বা কলব্যাক গ্রহণ করে যা অপারেশন সম্পূর্ণ হলে, বা অপারেশনের অগ্রগতির সময় অন্যান্য ইভেন্টের বিষয়ে অবহিত করা হয়।

একটি অ্যাসিঙ্ক্রোনাস API লেখার জন্য দুটি প্রাথমিক প্রেরণা রয়েছে:

  • একসাথে একাধিক অপারেশন চালানো, যেখানে N-1th অপারেশন শেষ হওয়ার আগে একটি Nth অপারেশন শুরু করতে হবে।
  • একটি অপারেশন সম্পূর্ণ না হওয়া পর্যন্ত একটি কলিং থ্রেড ব্লক করা এড়ানো।

Kotlin দৃঢ়ভাবে স্ট্রাকচার্ড কনকারেন্সি প্রচার করে, নীতিগুলির একটি সিরিজ এবং API গুলি সাসপেন্ড ফাংশনের উপর নির্মিত যা থ্রেড-ব্লকিং আচরণ থেকে কোডের সিঙ্ক্রোনাস এবং অ্যাসিঙ্ক্রোনাস এক্সিকিউশনকে ডিকপল করে। সাসপেন্ড ফাংশনগুলি ননব্লকিং এবং সিঙ্ক্রোনাস

স্থগিত ফাংশন:

  • তাদের কলিং থ্রেড অবরুদ্ধ করবেন না এবং অন্যত্র চালানো অপারেশনের ফলাফলের জন্য অপেক্ষা করার সময় তাদের এক্সিকিউশন থ্রেডটি বাস্তবায়নের বিশদ হিসাবে দিন।
  • সিঙ্ক্রোনাসভাবে এক্সিকিউট করুন এবং ননব্লকিং এপিআই-এর কলারকে এপিআই কল দ্বারা শুরু করা ননব্লকিং কাজের সাথে একযোগে কাজ চালিয়ে যেতে হবে না।

এই পৃষ্ঠাটি ননব্লকিং এবং অ্যাসিঙ্ক্রোনাস APIগুলির সাথে কাজ করার সময় বিকাশকারীরা নিরাপদে ধারণ করতে পারে এমন প্রত্যাশাগুলির একটি ন্যূনতম ভিত্তিরেখার বিবরণ দেয়, তারপরে এপিআইগুলি রচনার জন্য রেসিপিগুলির একটি সিরিজ যা কোটলিন বা জাভা ভাষায়, অ্যান্ড্রয়েড প্ল্যাটফর্ম বা জেটপ্যাক লাইব্রেরিতে এই প্রত্যাশাগুলি পূরণ করে৷ সন্দেহ হলে, কোনো নতুন API পৃষ্ঠের জন্য প্রয়োজনীয়তা হিসাবে বিকাশকারীর প্রত্যাশা বিবেচনা করুন।

async API-এর জন্য বিকাশকারীর প্রত্যাশা

নিম্নলিখিত প্রত্যাশাগুলি ননসসপেন্ডিং APIগুলির দৃষ্টিকোণ থেকে লেখা হয়েছে যদি না অন্যথায় উল্লেখ করা হয়৷

যে APIগুলি কলব্যাক গ্রহণ করে তা সাধারণত অ্যাসিঙ্ক্রোনাস হয়

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

একটি কলব্যাকের একটি উদাহরণ যা কেবলমাত্র ইন-প্লেস বলা হয় একটি উচ্চ-অর্ডার মানচিত্র বা ফিল্টার ফাংশন যা একটি ম্যাপারকে আহ্বান করে বা ফিরে আসার আগে একটি সংগ্রহের প্রতিটি আইটেমের পূর্বনির্ধারণ করে।

অ্যাসিঙ্ক্রোনাস API যত তাড়াতাড়ি সম্ভব ফিরে আসা উচিত

বিকাশকারীরা আশা করে যে async API গুলি অ-ব্লকিং হবে এবং অপারেশনের জন্য অনুরোধ শুরু করার পরে দ্রুত ফিরে আসবে। যে কোনো সময়ে একটি async API কল করা সর্বদা নিরাপদ হওয়া উচিত এবং একটি async API কল করার ফলে কখনই জ্যাঙ্কি ফ্রেম বা ANR হওয়া উচিত নয়।

প্ল্যাটফর্ম বা লাইব্রেরি অন-ডিমান্ড দ্বারা অনেক অপারেশন এবং লাইফসাইকেল সিগন্যাল ট্রিগার করা যেতে পারে এবং একজন ডেভেলপার তাদের কোডের জন্য সমস্ত সম্ভাব্য কল সাইটের বৈশ্বিক জ্ঞান ধারণ করার আশা করাটা টেকসই নয়। উদাহরণ স্বরূপ, উপলব্ধ স্থান (যেমন RecyclerView ) পূরণ করার জন্য অ্যাপের বিষয়বস্তু পপুলেট করা আবশ্যক হলে View পরিমাপ এবং লেআউটের প্রতিক্রিয়া হিসাবে একটি সিঙ্ক্রোনাস লেনদেনে FragmentManager একটি Fragment যোগ করা যেতে পারে। একটি LifecycleObserver এই টুকরোটির onStart লাইফসাইকেল কলব্যাকের প্রতিক্রিয়া জানাতে পারে এখানে যুক্তিসঙ্গতভাবে এককালীন স্টার্টআপ ক্রিয়াকলাপ সম্পাদন করতে পারে এবং এটি জ্যাঙ্ক মুক্ত অ্যানিমেশনের ফ্রেম তৈরির জন্য একটি গুরুত্বপূর্ণ কোডের পথে হতে পারে। একজন বিকাশকারীকে সর্বদা আত্মবিশ্বাসী বোধ করা উচিত যে এই ধরণের লাইফসাইকেল কলব্যাকের প্রতিক্রিয়া হিসাবে যে কোনও অ্যাসিঙ্ক এপিআই কল করা একটি জ্যাঙ্কি ফ্রেমের কারণ হবে না।

এটি বোঝায় যে ফিরে আসার আগে একটি async API দ্বারা সম্পাদিত কাজটি অবশ্যই খুব হালকা হতে হবে; অনুরোধ এবং সংশ্লিষ্ট কলব্যাকের একটি রেকর্ড তৈরি করা এবং এটিকে এক্সিকিউশন ইঞ্জিনের সাথে নিবন্ধন করা যা সর্বাধিক কাজ করে। যদি একটি async অপারেশনের জন্য নিবন্ধন করার জন্য IPC-এর প্রয়োজন হয়, তাহলে এপিআই-এর বাস্তবায়নকে ডেভেলপারের এই প্রত্যাশা পূরণের জন্য প্রয়োজনীয় সমস্ত ব্যবস্থা গ্রহণ করা উচিত। এর মধ্যে এক বা একাধিক অন্তর্ভুক্ত থাকতে পারে:

  • একমুখী বাইন্ডার কল হিসাবে একটি অন্তর্নিহিত IPC প্রয়োগ করা
  • সিস্টেম সার্ভারে একটি দ্বি-মুখী বাইন্ডার কল করা যেখানে নিবন্ধন সম্পূর্ণ করার জন্য একটি উচ্চ বিতর্কিত লক নেওয়ার প্রয়োজন হয় না
  • আইপিসি-তে ব্লকিং রেজিস্ট্রেশন করার জন্য অ্যাপ প্রক্রিয়ায় একজন কর্মী থ্রেডের কাছে অনুরোধ পোস্ট করা

অ্যাসিঙ্ক্রোনাস API গুলি অকার্যকর ফিরে আসা উচিত এবং শুধুমাত্র অবৈধ আর্গুমেন্টের জন্য নিক্ষেপ করা উচিত

Async APIগুলিকে অনুরোধ করা অপারেশনের সমস্ত ফলাফল প্রদত্ত কলব্যাকে রিপোর্ট করা উচিত৷ এটি বিকাশকারীকে সাফল্য এবং ত্রুটি পরিচালনার জন্য একটি একক কোড পথ প্রয়োগ করতে দেয়।

Async API গুলি null এবং throw NullPointerException জন্য আর্গুমেন্টগুলি পরীক্ষা করতে পারে , অথবা প্রদত্ত আর্গুমেন্টগুলি একটি বৈধ পরিসরের মধ্যে আছে কিনা তা পরীক্ষা করে দেখতে পারে এবং IllegalArgumentException নিক্ষেপ করতে পারে। উদাহরণস্বরূপ, একটি ফাংশন যা 0 থেকে 1f রেঞ্জের মধ্যে একটি float গ্রহণ করে, ফাংশনটি পরীক্ষা করতে পারে যে প্যারামিটারটি এই সীমার মধ্যে রয়েছে এবং যদি এটি সীমার বাইরে থাকে তবে একটি সংক্ষিপ্ত String একটি বৈধ বিন্যাসের সাথে সামঞ্জস্যের জন্য পরীক্ষা করা যেতে পারে যেমন IllegalArgumentException -শুধুমাত্র। (মনে রাখবেন যে সিস্টেম সার্ভারের কখনই অ্যাপ প্রক্রিয়াকে বিশ্বাস করা উচিত নয়! যেকোনো সিস্টেম পরিষেবার এই চেকগুলিকে সিস্টেম পরিষেবাতেই নকল করা উচিত।)

অন্যান্য সমস্ত ত্রুটি প্রদত্ত কলব্যাকে রিপোর্ট করা উচিত। এটি অন্তর্ভুক্ত, কিন্তু সীমাবদ্ধ নয়:

  • অনুরোধকৃত অপারেশনের টার্মিনাল ব্যর্থতা
  • অনুপস্থিত অনুমোদন বা অপারেশন সম্পূর্ণ করার জন্য প্রয়োজনীয় অনুমতিগুলির জন্য নিরাপত্তা ব্যতিক্রম
  • অপারেশন সম্পাদনের জন্য কোটা অতিক্রম করেছে৷
  • অ্যাপ প্রক্রিয়াটি অপারেশন করার জন্য যথেষ্ট "ফোরগ্রাউন্ড" নয়
  • প্রয়োজনীয় হার্ডওয়্যার সংযোগ বিচ্ছিন্ন করা হয়েছে
  • নেটওয়ার্ক ব্যর্থতা
  • টাইমআউট
  • বাইন্ডারের মৃত্যু বা অনুপলব্ধ দূরবর্তী প্রক্রিয়া

অ্যাসিঙ্ক্রোনাস এপিআই একটি বাতিল প্রক্রিয়া প্রদান করা উচিত

Async API-গুলিকে একটি চলমান ক্রিয়াকলাপের ইঙ্গিত দেওয়ার একটি উপায় প্রদান করা উচিত যে কলকারী আর ফলাফল সম্পর্কে চিন্তা করে না। এই বাতিল অপারেশন দুটি জিনিস সংকেত করা উচিত:

কলার দ্বারা প্রদত্ত কলব্যাকের হার্ড রেফারেন্স প্রকাশ করা উচিত

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

কলকারীর জন্য কাজ সম্পাদনকারী এক্সিকিউশন ইঞ্জিন সেই কাজটি বন্ধ করতে পারে

async API কল দ্বারা শুরু করা কাজ পাওয়ার খরচ বা অন্যান্য সিস্টেম রিসোর্সে উচ্চ খরচ বহন করতে পারে। এপিআইগুলি যেগুলি কলারকে সংকেত দেওয়ার অনুমতি দেয় যখন এই কাজটির আর প্রয়োজন হয় না তখন এটি আরও সিস্টেম সংস্থানগুলি ব্যবহার করার আগে সেই কাজটি বন্ধ করার অনুমতি দেয়৷

ক্যাশে বা হিমায়িত অ্যাপের জন্য বিশেষ বিবেচনা

অ্যাসিঙ্ক্রোনাস এপিআই ডিজাইন করার সময় যেখানে কলব্যাকগুলি একটি সিস্টেম প্রক্রিয়ায় উদ্ভূত হয় এবং অ্যাপগুলিতে বিতরণ করা হয়, নিম্নলিখিতগুলি বিবেচনা করুন:

  1. প্রসেস এবং অ্যাপ লাইফসাইকেল : প্রাপক অ্যাপ প্রক্রিয়া ক্যাশে অবস্থায় থাকতে পারে।
  2. ক্যাশড অ্যাপস ফ্রিজার : প্রাপক অ্যাপ প্রক্রিয়া হিমায়িত হতে পারে।

যখন একটি অ্যাপ প্রক্রিয়া ক্যাশে করা অবস্থায় প্রবেশ করে, এর মানে হল যে এটি সক্রিয়ভাবে কোনো ব্যবহারকারী-দৃশ্যমান উপাদান যেমন কার্যকলাপ এবং পরিষেবাগুলি হোস্ট করছে না। অ্যাপটি মেমরিতে রাখা হয় যদি এটি আবার ব্যবহারকারী-দৃশ্যমান হয়, তবে এর মধ্যে কাজ করা উচিত নয়। বেশিরভাগ ক্ষেত্রে, যখন অ্যাপটি ক্যাশ করা অবস্থায় প্রবেশ করে তখন আপনার অ্যাপ কলব্যাক পাঠানো বন্ধ করা উচিত এবং অ্যাপটি ক্যাশ করা অবস্থায় প্রস্থান করার সময় পুনরায় শুরু করা উচিত, যাতে ক্যাশ করা অ্যাপ প্রক্রিয়াগুলিতে কাজ না হয়।

একটি ক্যাশে করা অ্যাপও হিমায়িত হতে পারে। যখন একটি অ্যাপ হিমায়িত হয়, তখন এটি শূন্য CPU সময় পায় এবং কোনো কাজ করতে সক্ষম হয় না। সেই অ্যাপের নিবন্ধিত কলব্যাকে যেকোন কল বাফার করা হয় এবং অ্যাপটি আনফ্রোজ করা হলে ডেলিভারি করা হয়।

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

পর্যালোচনায়:

  • অ্যাপের প্রক্রিয়াটি ক্যাশে থাকা অবস্থায় আপনার অ্যাপ কলব্যাক পাঠানোর বিরতি বিবেচনা করা উচিত।
  • অ্যাপের প্রক্রিয়াটি হিমায়িত থাকা অবস্থায় আপনাকে অবশ্যই অ্যাপ কলব্যাক প্রেরণে বিরতি দিতে হবে।

রাষ্ট্র ট্র্যাকিং

অ্যাপ্লিকেশানগুলি কখন ক্যাশ করা অবস্থায় প্রবেশ করে বা প্রস্থান করে তা ট্র্যাক করতে:

mActivityManager.addOnUidImportanceListener(
    new UidImportanceListener() { ... },
    IMPORTANCE_CACHED);

অ্যাপগুলি কখন হিমায়িত বা আনফ্রোজ করা হয় তা ট্র্যাক করতে:

IBinder binder = <...>;
binder.addFrozenStateChangeCallback(executor, callback);

অ্যাপ কলব্যাক পাঠানো আবার শুরু করার কৌশল

অ্যাপটি ক্যাশ করা অবস্থায় বা হিমায়িত অবস্থায় প্রবেশ করলে আপনি অ্যাপের কলব্যাকগুলিকে বিরাম দিন না কেন, অ্যাপটি যখন সংশ্লিষ্ট রাজ্য থেকে প্রস্থান করে তখন অ্যাপটি তার কলব্যাক নিবন্ধনমুক্ত না হওয়া পর্যন্ত বা অ্যাপের প্রক্রিয়াটি শেষ না হওয়া পর্যন্ত অ্যাপটি সংশ্লিষ্ট রাজ্য থেকে প্রস্থান করার পরে আপনাকে অ্যাপের নিবন্ধিত কলব্যাকগুলি পাঠানো আবার শুরু করতে হবে।

যেমন:

IBinder binder = <...>;
bool shouldSendCallbacks = true;
binder.addFrozenStateChangeCallback(executor, (who, state) -> {
    if (state == IBinder.FrozenStateChangeCallback.STATE_FROZEN) {
        shouldSendCallbacks = false;
    } else if (state == IBinder.FrozenStateChangeCallback.STATE_UNFROZEN) {
        shouldSendCallbacks = true;
    }
});

বিকল্পভাবে, আপনি RemoteCallbackList ব্যবহার করতে পারেন যা হিমায়িত অবস্থায় টার্গেট প্রক্রিয়ায় কলব্যাক সরবরাহ না করার যত্ন নেয়।

যেমন:

RemoteCallbackList<IInterface> rc =
        new RemoteCallbackList.Builder<IInterface>(
                        RemoteCallbackList.FROZEN_CALLEE_POLICY_DROP)
                .setExecutor(executor)
                .build();
rc.register(callback);
rc.broadcast((callback) -> callback.foo(bar));

callback.foo() শুধুমাত্র প্রক্রিয়াটি হিমায়িত না হলেই আহ্বান করা হয়।

অ্যাপগুলি প্রায়ই সাম্প্রতিক অবস্থার স্ন্যাপশট হিসাবে কলব্যাক ব্যবহার করে প্রাপ্ত আপডেটগুলি সংরক্ষণ করে। অবশিষ্ট ব্যাটারি শতাংশ নিরীক্ষণ করার জন্য অ্যাপ্লিকেশনগুলির জন্য একটি অনুমানমূলক API বিবেচনা করুন:

interface BatteryListener {
    void onBatteryPercentageChanged(int newPercentage);
}

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

RemoteCallbackList<IInterface> rc =
        new RemoteCallbackList.Builder<IInterface>(
                        RemoteCallbackList.FROZEN_CALLEE_POLICY_ENQUEUE_MOST_RECENT)
                .setExecutor(executor)
                .build();
rc.register(callback);
rc.broadcast((callback) -> callback.onBatteryPercentageChanged(value));

কিছু ক্ষেত্রে, আপনি অ্যাপে বিতরিত শেষ মানটি ট্র্যাক করতে পারেন যাতে অ্যাপটিকে আনফ্রোজ করার পরে একই মান সম্পর্কে অবহিত করার প্রয়োজন হয় না।

রাষ্ট্র আরো জটিল তথ্য হিসাবে প্রকাশ করা যেতে পারে. নেটওয়ার্ক ইন্টারফেস সম্পর্কে অবহিত করার জন্য অ্যাপ্লিকেশনগুলির জন্য একটি অনুমানমূলক API বিবেচনা করুন:

interface NetworkListener {
    void onAvailable(Network network);
    void onLost(Network network);
    void onChanged(Network network);
}

একটি অ্যাপে বিজ্ঞপ্তিগুলিকে বিরতি দেওয়ার সময়, আপনার মনে রাখা উচিত যে নেটওয়ার্কগুলির সেট এবং অ্যাপটি শেষবার দেখেছিল। পুনরায় শুরু করার পরে, এই ক্রমানুসারে, পুরানো নেটওয়ার্কগুলি যেগুলি হারিয়ে গেছে, নতুন নেটওয়ার্কগুলি যেগুলি উপলব্ধ হয়েছে এবং বিদ্যমান নেটওয়ার্কগুলির যেগুলির অবস্থা পরিবর্তিত হয়েছে - সেগুলির অ্যাপকে জানানোর পরামর্শ দেওয়া হচ্ছে৷

যে নেটওয়ার্কগুলি উপলব্ধ করা হয়েছিল এবং তারপরে কলব্যাকগুলি থামানোর সময় হারিয়ে গেছে সেগুলির অ্যাপটিকে অবহিত করবেন না৷ অ্যাপগুলিকে হিমায়িত করার সময় ঘটে যাওয়া ইভেন্টগুলির সম্পূর্ণ অ্যাকাউন্ট পাওয়া উচিত নয় এবং API ডকুমেন্টেশনগুলি স্পষ্ট জীবনচক্র অবস্থার বাইরে নিরবচ্ছিন্নভাবে ইভেন্ট স্ট্রিমগুলি সরবরাহ করার প্রতিশ্রুতি দেওয়া উচিত নয়। এই উদাহরণে, যদি অ্যাপটিকে ক্রমাগত নেটওয়ার্ক উপলব্ধতা নিরীক্ষণ করতে হয় তবে এটি অবশ্যই একটি লাইফসাইকেল অবস্থায় থাকতে হবে যা এটিকে ক্যাশে বা হিমায়িত হওয়া থেকে বিরত রাখে।

পর্যালোচনায়, আপনাকে বিরতির পরে এবং বিজ্ঞপ্তিগুলি পুনরায় শুরু করার আগে ঘটে যাওয়া ইভেন্টগুলিকে একত্রিত করা উচিত এবং সংক্ষিপ্তভাবে নিবন্ধিত অ্যাপ কলব্যাকগুলিতে সর্বশেষ অবস্থা সরবরাহ করা উচিত।

বিকাশকারী ডকুমেন্টেশন জন্য বিবেচনা

অ্যাসিঙ্ক ইভেন্টগুলির ডেলিভারি বিলম্বিত হতে পারে, কারণ প্রেরক পূর্ববর্তী বিভাগে দেখানো সময়ের জন্য ডেলিভারি থামিয়ে দিয়েছে বা প্রাপক অ্যাপ সময়মত ইভেন্ট প্রক্রিয়া করার জন্য পর্যাপ্ত ডিভাইস সংস্থান পায়নি।

ডেভেলপারদের অনুমান করতে নিরুৎসাহিত করুন যখন তাদের অ্যাপ একটি ইভেন্ট সম্পর্কে অবহিত করা হয় এবং ঘটনাটি আসলে ঘটেছিল সেই সময়ের মধ্যে।

এপিআই স্থগিত করার জন্য বিকাশকারীর প্রত্যাশা

কোটলিনের স্ট্রাকচার্ড কনকারেন্সির সাথে পরিচিত ডেভেলপাররা যেকোন স্থগিত API থেকে নিম্নলিখিত আচরণগুলি আশা করে:

সাসপেন্ড ফাংশনগুলি রিটার্ন বা থ্রো করার আগে সমস্ত সম্পর্কিত কাজ সম্পূর্ণ করা উচিত

ননব্লকিং ক্রিয়াকলাপের ফলাফলগুলি স্বাভাবিক ফাংশন রিটার্ন মান হিসাবে ফেরত দেওয়া হয় এবং ব্যতিক্রমগুলি নিক্ষেপ করে ত্রুটিগুলি রিপোর্ট করা হয়। (এর মানে প্রায়ই কলব্যাক প্যারামিটার অপ্রয়োজনীয়।)

স্থগিত ফাংশন শুধুমাত্র কলব্যাক প্যারামিটার ইন-প্লেস করা উচিত

সাসপেন্ড ফাংশনগুলি সর্বদা ফিরে আসার আগে সমস্ত সম্পর্কিত কাজ সম্পূর্ণ করা উচিত, তাই তাদের কখনই প্রদত্ত কলব্যাক বা অন্যান্য ফাংশন প্যারামিটার আহ্বান করা উচিত নয় বা সাসপেন্ড ফাংশন ফিরে আসার পরে এটির একটি রেফারেন্স রাখা উচিত নয়।

স্থগিত ফাংশন যে কলব্যাক পরামিতি গ্রহণ করে প্রসঙ্গ-সংরক্ষণ করা উচিত যদি না অন্যথায় নথিভুক্ত করা হয়

একটি সাসপেন্ড ফাংশনে একটি ফাংশন কল করার ফলে এটি কলারের CoroutineContext এ চলে। যেহেতু সাসপেন্ড ফাংশনগুলি রিটার্ন বা থ্রো করার আগে সমস্ত সম্পর্কিত কাজ সম্পন্ন করা উচিত, এবং শুধুমাত্র কলব্যাক প্যারামিটারগুলিকে ইন-প্লেস করা উচিত, ডিফল্ট প্রত্যাশা হল যে এই ধরনের যেকোন কলব্যাকগুলি কলিং CoroutineContext এর সাথে যুক্ত প্রেরক ব্যবহার করে চালানো হয়৷ যদি API এর উদ্দেশ্য হয় কলিং CoroutineContext এর বাইরে একটি কলব্যাক চালানো, এই আচরণটি স্পষ্টভাবে নথিভুক্ত করা উচিত।

স্থগিত ফাংশন kotlinx.coroutines চাকরি বাতিলকে সমর্থন করবে

kotlinx.coroutines দ্বারা সংজ্ঞায়িত যে কোনও স্থগিত ফাংশন অফার করা চাকরি বাতিলের সাথে সহযোগিতা করা উচিত। যদি প্রগতিশীল একটি অপারেশনের কলিং কাজ বাতিল করা হয়, ফাংশনটি যত তাড়াতাড়ি সম্ভব একটি CancellationException দিয়ে পুনরায় শুরু করা উচিত যাতে কলকারী যত তাড়াতাড়ি সম্ভব পরিষ্কার করতে এবং চালিয়ে যেতে পারে। এটি suspendCancellableCoroutine এবং kotlinx.coroutines দ্বারা অফার করা অন্যান্য সাসপেন্ডিং API দ্বারা স্বয়ংক্রিয়ভাবে পরিচালনা করা হয়। লাইব্রেরি বাস্তবায়নে সাধারণত suspendCoroutine সরাসরি ব্যবহার করা উচিত নয়, কারণ এটি ডিফল্টরূপে এই বাতিলকরণ আচরণকে সমর্থন করে না।

স্থগিত ফাংশনগুলি যেগুলি একটি ব্যাকগ্রাউন্ডে ব্লক করার কাজ সম্পাদন করে (নন-মেইন বা UI থ্রেড) অবশ্যই ব্যবহৃত ডিসপ্যাচার কনফিগার করার একটি উপায় প্রদান করবে

থ্রেড স্যুইচ করার জন্য একটি ব্লকিং ফাংশন সম্পূর্ণরূপে স্থগিত করার সুপারিশ করা হয় না

একটি সাসপেন্ড ফাংশন কল করার ফলে ডেভেলপারকে সেই কাজটি সম্পাদন করার জন্য তাদের নিজস্ব থ্রেড বা থ্রেড পুল সরবরাহ করার অনুমতি না দিয়ে অতিরিক্ত থ্রেড তৈরি করা উচিত নয়। উদাহরণস্বরূপ, একজন কনস্ট্রাক্টর একটি CoroutineContext গ্রহণ করতে পারে যা ক্লাসের পদ্ধতিগুলির জন্য ব্যাকগ্রাউন্ড কাজ সম্পাদন করতে ব্যবহৃত হয়।

যে ফাংশনগুলি একটি ঐচ্ছিক CoroutineContext বা Dispatcher প্যারামিটার গ্রহণ করবে শুধুমাত্র সেই প্রেরককে ব্লক করার কাজ সম্পাদন করার জন্য স্থগিত করবে তার পরিবর্তে অন্তর্নিহিত ব্লকিং ফাংশনটি প্রকাশ করা উচিত এবং সুপারিশ করা উচিত যে কলিং ডেভেলপাররা একটি নির্বাচিত প্রেরককে কাজটি পরিচালনা করতে withContext-এ তাদের নিজস্ব কল ব্যবহার করে৷

ক্লাস শুরু করুটিন

যে ক্লাসগুলি কোরোটিনগুলি লঞ্চ করে তাদের অবশ্যই সেই লঞ্চ অপারেশনগুলি সম্পাদন করার জন্য একটি CoroutineScope থাকতে হবে৷ স্ট্রাকচার্ড কনকারেন্সি নীতিগুলিকে সম্মান করা সেই সুযোগটি পাওয়ার এবং পরিচালনার জন্য নিম্নলিখিত কাঠামোগত নিদর্শনগুলিকে বোঝায়।

একটি ক্লাস লেখার আগে যা সমসাময়িক কাজগুলিকে অন্য সুযোগে চালু করে, বিকল্প নিদর্শনগুলি বিবেচনা করুন:

class MyClass {
    private val requests = Channel<MyRequest>(Channel.UNLIMITED)

    suspend fun handleRequests() {
        coroutineScope {
            for (request in requests) {
                // Allow requests to be processed concurrently;
                // alternatively, omit the [launch] and outer [coroutineScope]
                // to process requests serially
                launch {
                    processRequest(request)
                }
            }
        }
    }

    fun submitRequest(request: MyRequest) {
        requests.trySend(request).getOrThrow()
    }
}

সমসাময়িক কাজ সম্পাদন করার জন্য একটি suspend fun প্রকাশ করা কলারকে তাদের নিজস্ব প্রেক্ষাপটে ক্রিয়াকলাপটি শুরু করার অনুমতি দেয়, MyClass একটি CoroutineScope পরিচালনা করার প্রয়োজনীয়তা দূর করে৷ রিকোয়েস্টের প্রসেসিংকে সিরিয়ালাইজ করা সহজ হয়ে যায় এবং স্টেট প্রায়শই handleRequests লোকাল ভেরিয়েবল হিসেবে বর্গ বৈশিষ্ট্যের পরিবর্তে থাকতে পারে যার অন্যথায় অতিরিক্ত সিঙ্ক্রোনাইজেশন প্রয়োজন হবে।

যে ক্লাসগুলি করোটিনগুলি পরিচালনা করে তাদের বন্ধ এবং বাতিল পদ্ধতিগুলি প্রকাশ করা উচিত

যে ক্লাসগুলি কর্উটিনগুলিকে বাস্তবায়নের বিবরণ হিসাবে চালু করে তাদের অবশ্যই সেই চলমান সমসাময়িক কাজগুলিকে পরিষ্কারভাবে বন্ধ করার একটি উপায় দিতে হবে যাতে তারা অভিভাবক সুযোগে অনিয়ন্ত্রিত সমকালীন কাজগুলিকে ফাঁস না করে। সাধারণত এটি একটি প্রদত্ত CoroutineContext এর একটি চাইল্ড Job তৈরির রূপ নেয়:

private val myJob = Job(parent = `CoroutineContext`[Job])
private val myScope = CoroutineScope(`CoroutineContext` + myJob)

fun cancel() {
    myJob.cancel()
}

একটি join() পদ্ধতিও প্রদান করা যেতে পারে যাতে ব্যবহারকারীর কোড অবজেক্টের দ্বারা সম্পাদিত কোনো অসামান্য সমবর্তী কাজ সমাপ্তির জন্য অপেক্ষা করতে পারে। (এর মধ্যে একটি অপারেশন বাতিল করে পরিচ্ছন্নতার কাজ অন্তর্ভুক্ত থাকতে পারে।)

suspend fun join() {
    myJob.join()
}

টার্মিনাল অপারেশন নামকরণ

পদ্ধতিগুলির জন্য ব্যবহৃত নাম যা এখনও চলছে এমন একটি বস্তুর মালিকানাধীন সমসাময়িক কাজগুলিকে পরিষ্কারভাবে বন্ধ করে দেয় যেটি কীভাবে শাটডাউন ঘটে তার আচরণগত চুক্তিকে প্রতিফলিত করা উচিত:

যখন চলমান অপারেশনগুলি সম্পূর্ণ হতে পারে তখন close() ব্যবহার করুন কিন্তু close() কল রিটার্ন করার পরে কোনও নতুন অপারেশন শুরু হবে না।

cancel() ব্যবহার করুন যখন ক্রিয়াকলাপগুলি সম্পূর্ণ হওয়ার আগে বাতিল হতে পারে। cancel() কল ফেরত আসার পর কোনো নতুন ক্রিয়াকলাপ শুরু হবে না।

ক্লাস কনস্ট্রাক্টররা CoroutineContext স্বীকার করে, CoroutineScope নয়

যখন বস্তুগুলিকে প্রদত্ত প্যারেন্ট স্কোপে সরাসরি লঞ্চ করা নিষিদ্ধ করা হয়, তখন কন্সট্রাকটর প্যারামিটার হিসাবে CoroutineScope এর উপযুক্ততা ভেঙে যায়:

// Don't do this
class MyClass(scope: CoroutineScope) {
    private val myJob = Job(parent = scope.`CoroutineContext`[Job])
    private val myScope = CoroutineScope(scope.`CoroutineContext` + myJob)

    // ... the [scope] constructor parameter is never used again
}

CoroutineScope একটি অপ্রয়োজনীয় এবং বিভ্রান্তিকর মোড়ক হয়ে ওঠে যা কিছু ব্যবহারের ক্ষেত্রে শুধুমাত্র একটি কনস্ট্রাক্টর প্যারামিটার হিসাবে পাস করার জন্য তৈরি করা যেতে পারে, শুধুমাত্র বাতিল করতে হবে:

// Don't do this; just pass the context
val myObject = MyClass(CoroutineScope(parentScope.`CoroutineContext` + Dispatchers.IO))

CoroutineContext প্যারামিটার ডিফল্ট EmptyCoroutineContext

যখন একটি ঐচ্ছিক CoroutineContext প্যারামিটার একটি API পৃষ্ঠে উপস্থিত হয় তখন ডিফল্ট মান অবশ্যই Empty`CoroutineContext` CoroutineContext` সেন্টিনেল হতে হবে। এটি API আচরণের আরও ভাল রচনার জন্য অনুমতি দেয়, যেহেতু একজন কলার থেকে একটি Empty`CoroutineContext` মান ডিফল্ট গ্রহণ করার মতো একইভাবে আচরণ করা হয়:

class MyOuterClass(
    `CoroutineContext`: `CoroutineContext` = Empty`CoroutineContext`
) {
    private val innerObject = MyInnerClass(`CoroutineContext`)

    // ...
}

class MyInnerClass(
    `CoroutineContext`: `CoroutineContext` = Empty`CoroutineContext`
) {
    private val job = Job(parent = `CoroutineContext`[Job])
    private val scope = CoroutineScope(`CoroutineContext` + job)

    // ...
}