আপনার অ্যাপকে রেসপন্সিভ রাখা

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

এই ডকুমেন্ট থেকে জানা যায় যে কীভাবে Android সিস্টেম নির্ধারণ করে যে কোনও অ্যাপ রেসপন্স করছে না এবং আপনার অ্যাপকে কীভাবে রেসপন্সিভ রাখবেন তা দেখায়।

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

ANR ট্রিগার

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

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

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

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

ANR এড়িয়ে চলুন

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

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

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

    • প্রধান থ্রেড এবং অন্যান্য থ্রেডের মধ্যে যেকোনও লক কনটেনশন কমানোর চেষ্টা করুন।

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

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

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

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

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

BroadcastReceiver-এ ANR

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

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

রেসপন্সিভনেস আরও উন্নত করুন

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

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

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

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

  • আপনার অ্যাপের রেসপন্সিভনেসের ক্ষেত্রে বাধা নির্ধারণ করতে Perfetto এবং CPU Profiler-এর মতো পারফর্ম্যান্স টুল ব্যবহার করুন।