আপনার অ্যাপ্লিকেশন প্রতিক্রিয়াশীল রাখুন

চিত্র ১. ব্যবহারকারীকে দেখানো একটি ANR ডায়ালগ।

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

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

ANR ট্রিগার

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

উদাহরণস্বরূপ, কোনো অ্যাপ যদি UI থ্রেডে নেটওয়ার্ক অ্যাক্সেসের মতো কোনো ব্লকিং I/O অপারেশন সম্পাদন করে, তাহলে একটি ANR ঘটতে পারে। আরেকটি উদাহরণ হলো, যখন কোনো অ্যাপ UI থ্রেডে একটি জটিল ইন-মেমরি কাঠামো তৈরি করতে বা কোনো গেমে পরবর্তী চাল গণনা করতে অতিরিক্ত সময় ব্যয় করে।

অ্যান্ড্রয়েডে, অ্যাপের রেসপন্সিভনেস ActivityManager এবং WindowManager সিস্টেম সার্ভিস দ্বারা পর্যবেক্ষণ করা হয়। অ্যান্ড্রয়েড নিম্নলিখিত শর্তগুলির মধ্যে একটি শনাক্ত করলে কোনো অ্যাপের জন্য ANR ডায়ালগ প্রদর্শন করে:

  • ৫ সেকেন্ডের মধ্যে কোনো ইনপুট ইভেন্টে—যেমন কী-প্রেস বা স্ক্রিন ট্যাপ ইভেন্ট—কোনো সাড়া না দেওয়া।
  • ফোরগ্রাউন্ড ইন্টেন্টের ক্ষেত্রে, একটি BroadcastReceiver ১০ থেকে ২০ সেকেন্ডের মধ্যে তার কার্য সম্পাদন শেষ করে না। আরও তথ্যের জন্য, Broadcast receiver timeout দেখুন।

এএনআর এড়িয়ে চলুন

ANR এড়ানোর জন্য নিম্নলিখিতগুলি সাধারণ পরামর্শ। বিভিন্ন ধরণের ANR নির্ণয় ও ডিবাগিং সম্পর্কে আরও বিস্তারিত জানতে এই বিভাগের অন্যান্য পৃষ্ঠাগুলি দেখুন।

  • প্রধান থ্রেডকে সর্বদা আনব্লকড রাখুন এবং কৌশলগতভাবে থ্রেড ব্যবহার করুন।

    • অ্যাপের প্রধান থ্রেডে ব্লকিং বা দীর্ঘ সময় ধরে চলা অপারেশনগুলো সম্পাদন করবেন না। এর পরিবর্তে, কাজটি ব্যাকগ্রাউন্ড ডিসপ্যাচারগুলিতে (যেমন Dispatchers.IO বা Dispatchers.Default ) স্থানান্তর করতে কোটলিন কোরাউটিন ব্যবহার করুন। এই ব্যাকগ্রাউন্ড টাস্কগুলো নিরাপদে চালু করতে viewModelScope মতো মেকানিজম ব্যবহার করুন, অথবা Compose স্টেট পরিবর্তনের প্রতিক্রিয়ায় সেগুলোকে ট্রিগার করতে LaunchedEffect

    • প্রধান থ্রেড এবং অন্যান্য থ্রেডগুলির মধ্যে লক নিয়ে যেকোনো ধরনের দ্বন্দ্ব যথাসম্ভব কমানোর চেষ্টা করুন।

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

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

  • অ্যাপের স্টার্টআপ দ্রুত রাখুন। অ্যাপের স্টার্টআপ কোডে ধীরগতির বা বাধা সৃষ্টিকারী অপারেশনগুলো কমিয়ে আনুন, যেমন ডিপেন্ডেন্সি ইনজেকশন সেটআপের সময় ( Hilt- এর মতো) রান হওয়া মেথড অথবা Jetpack App Startup লাইব্রেরি ব্যবহার করে ইনিশিয়ালাইজ করা কম্পোনেন্ট। আপনি Baseline Profiles , Startup Profiles , এবং R8 ব্যবহার করে অ্যাপ স্টার্টআপকে আরও অপ্টিমাইজ করতে পারেন।

  • আপনি যদি BroadcastReceiver ব্যবহার করেন, তাহলে Context.registerReceiver ব্যবহার করে ব্রডকাস্ট রিসিভারগুলোকে একটি নন-মেইন থ্রেডে চালানোর কথা বিবেচনা করুন। আরও তথ্যের জন্য, BroadcastReceiver-এ ANRs দেখুন।

    • আপনি যদি goAsync ব্যবহার করেন, তাহলে নিশ্চিত করুন যেন ANR টাইমআউটের আগেই PendingResult.finish দ্রুত কল করা হয়।

ব্রডকাস্ট রিসিভারে ANRs

BroadcastReceiver এক্সিকিউশন টাইম সীমিত, কারণ এর কাজ হলো ব্যাকগ্রাউন্ডে অল্প পরিমাণে বিচ্ছিন্ন কাজ করা, যেমন কোনো সেটিং সেভ করা বা একটি Notification রেজিস্টার করা। তাই, UI থ্রেডে কল করা অন্যান্য মেথডের মতোই, অ্যাপগুলোকে অবশ্যই ব্রডকাস্ট রিসিভারে সম্ভাব্য দীর্ঘ সময় ধরে চলা অপারেশন বা ক্যালকুলেশন এড়িয়ে চলতে হবে। UI থ্রেডের মাধ্যমে দীর্ঘ সময় ধরে চলা কাজগুলো সম্পাদন না করে, সেগুলোকে পরে সম্পাদনের জন্য ব্যাকগ্রাউন্ডে সম্পন্ন করুন। সম্ভাব্য সমাধান সম্পর্কে আরও তথ্যের জন্য ‘ব্যাকগ্রাউন্ড টাস্ক ওভারভিউ’ দেখুন।

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

প্রতিক্রিয়াশীলতা জোরদার করুন

সাধারণত, ১০০ থেকে ২০০ মিলিসেকেন্ড হলো সেই সীমা, যার বাইরে গেলে ব্যবহারকারীরা অ্যাপটিকে ধীর বলে মনে করেন। আপনার অ্যাপটিকে ব্যবহারকারীদের কাছে আরও বেশি রেসপন্সিভ করে তোলার জন্য এখানে কিছু অতিরিক্ত টিপস দেওয়া হলো:

  • আপনার অ্যাপ যদি ব্যবহারকারীর ইনপুটের প্রতিক্রিয়ায় ব্যাকগ্রাউন্ডে কোনো কাজ করে, তাহলে UI-তে CircularProgressIndicator বা LinearProgressIndicator মাধ্যমে কাজের অগ্রগতি দেখান।

  • বিশেষ করে গেমের ক্ষেত্রে, চাল দেওয়ার হিসাব-নিকাশ একটি ব্যাকগ্রাউন্ড কো-রুটিন বা ওয়ার্কার থ্রেডে করুন।

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

  • আপনার অ্যাপের রেসপন্সিভনেসের প্রতিবন্ধকতাগুলো শনাক্ত করতে পারফেটটো এবং সিপিইউ প্রোফাইলারের মতো পারফরম্যান্স টুল ব্যবহার করুন।