ANR

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

চিত্র 1. ANR ডায়ালগ ব্যবহারকারীর কাছে প্রদর্শিত হয়

চিত্র 1. ANR ডায়ালগ ব্যবহারকারীর কাছে প্রদর্শিত হয়

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

নিম্নলিখিত শর্তগুলির মধ্যে একটি ঘটলে আপনার অ্যাপের জন্য একটি ANR ট্রিগার হয়:

  • ইনপুট পাঠানোর সময় শেষ: আপনার অ্যাপ যদি 5 সেকেন্ডের মধ্যে কোনো ইনপুট ইভেন্টে (যেমন কী প্রেস বা স্ক্রিন টাচ) সাড়া না দেয়।
  • এক্সিকিউটিং সার্ভিস: যদি আপনার অ্যাপের দ্বারা ঘোষিত কোনো সার্ভিস কয়েক সেকেন্ডের মধ্যে Service.onCreate() এবং Service.onStartCommand() / Service.onBind() চালানো শেষ করতে না পারে।
  • Service.startForeground() কল করা হয়নি: যদি আপনার অ্যাপটি ফোরগ্রাউন্ডে একটি নতুন পরিষেবা শুরু করতে Context.startForegroundService() ব্যবহার করে, কিন্তু পরিষেবাটি 5 সেকেন্ডের মধ্যে startForeground() কল করে না।
  • অভিপ্রায় সম্প্রচার: যদি একটি BroadcastReceiver একটি নির্দিষ্ট সময়ের মধ্যে কার্যকর করা শেষ না করে। অ্যাপটির অগ্রভাগে কোনো কার্যকলাপ থাকলে, এই সময়সীমাটি 5 সেকেন্ড।
  • JobScheduler ইন্টারঅ্যাকশন: যদি কয়েক সেকেন্ডের মধ্যে JobService.onStartJob() বা JobService.onStopJob() থেকে কোনও JobService ফিরে না আসে, অথবা যদি কোনও ব্যবহারকারীর দ্বারা শুরু করা কাজ শুরু হয় এবং আপনার অ্যাপ কয়েক সেকেন্ডের মধ্যে JobService.setNotification() কল না করে JobService.onStartJob() কল করার পর। অ্যান্ড্রয়েড 13 এবং তার নিচের অ্যাপ্লিকেশানগুলির জন্য, ANRগুলি নীরব থাকে এবং অ্যাপে রিপোর্ট করা হয় না। অ্যান্ড্রয়েড 14 এবং তার উপরে লক্ষ্য করা অ্যাপগুলির জন্য, ANRগুলি স্পষ্ট এবং অ্যাপে রিপোর্ট করা হয়।

আপনার অ্যাপ যদি ANR-এর সম্মুখীন হয়, তাহলে আপনি সমস্যাটি নির্ণয় করতে এবং সমাধান করতে এই নিবন্ধে দেওয়া নির্দেশিকা ব্যবহার করতে পারেন।

সমস্যাটি সনাক্ত করুন

আপনি যদি ইতিমধ্যেই আপনার অ্যাপ প্রকাশ করে থাকেন, তাহলে আপনি আপনার অ্যাপের ANR-এর তথ্য দেখতে Android ভাইটাল ব্যবহার করতে পারেন। আপনি ক্ষেত্রে ANR সনাক্ত করতে অন্যান্য সরঞ্জামগুলি ব্যবহার করতে পারেন তবে মনে রাখবেন যে 3P সরঞ্জামগুলি Android এর পুরানো সংস্করণগুলিতে (Android 10 এবং নীচের) ANRগুলি রিপোর্ট করতে পারে না, Android ভাইটালগুলির বিপরীতে৷

অ্যান্ড্রয়েড গুরুত্বপূর্ণ

Android ভাইটাল আপনাকে আপনার অ্যাপের ANR রেট নিরীক্ষণ এবং উন্নত করতে সাহায্য করতে পারে। অ্যান্ড্রয়েড ভাইটাল বিভিন্ন ANR হার পরিমাপ করে:

  • ANR হার: আপনার দৈনিক সক্রিয় ব্যবহারকারীদের শতাংশ যারা যেকোন ধরনের ANR-এর অভিজ্ঞতা পেয়েছেন।
  • ব্যবহারকারী-অনুভূত ANR হার: আপনার দৈনিক সক্রিয় ব্যবহারকারীদের শতাংশ যারা কমপক্ষে একজন ব্যবহারকারী-অনুভূত ANR-এর অভিজ্ঞতা পেয়েছেন। বর্তমানে শুধুমাত্র ANR টাইপ Input dispatching timed out ব্যবহারকারীর দ্বারা অনুভূত বলে বিবেচিত হয়।
  • একাধিক ANR হার: আপনার দৈনিক সক্রিয় ব্যবহারকারীদের শতাংশ যারা কমপক্ষে দুটি ANR-এর অভিজ্ঞতা পেয়েছেন।

একজন দৈনিক সক্রিয় ব্যবহারকারী একজন অনন্য ব্যবহারকারী যিনি আপনার অ্যাপটি একক ডিভাইসে একটি দিনে ব্যবহার করেন, সম্ভাব্য একাধিক সেশনে। যদি একজন ব্যবহারকারী এক দিনে একাধিক ডিভাইসে আপনার অ্যাপ ব্যবহার করেন, প্রতিটি ডিভাইস সেই দিনের জন্য সক্রিয় ব্যবহারকারীর সংখ্যায় অবদান রাখবে। যদি একাধিক ব্যবহারকারী এক দিনে একই ডিভাইস ব্যবহার করেন তবে এটি একজন সক্রিয় ব্যবহারকারী হিসাবে গণনা করা হবে।

ব্যবহারকারী-অনুভূত ANR রেট হল একটি গুরুত্বপূর্ণ অত্যাবশ্যক যার অর্থ এটি Google Play-তে আপনার অ্যাপের আবিষ্কারযোগ্যতাকে প্রভাবিত করে। এটি গুরুত্বপূর্ণ কারণ এটির গণনা করা ANRগুলি সর্বদা ঘটে যখন ব্যবহারকারী অ্যাপের সাথে জড়িত থাকে, যার ফলে সবচেয়ে বেশি ব্যাঘাত ঘটে।

Play এই মেট্রিকে দুটি খারাপ আচরণের থ্রেশহোল্ড সংজ্ঞায়িত করেছে:

  • সামগ্রিকভাবে খারাপ আচরণের থ্রেশহোল্ড: দৈনিক সক্রিয় ব্যবহারকারীদের অন্তত 0.47% সমস্ত ডিভাইস মডেল জুড়ে ব্যবহারকারী-অনুভূত ANR অনুভব করে।
  • প্রতি-ডিভাইস খারাপ আচরণের থ্রেশহোল্ড: দৈনিক ব্যবহারকারীদের অন্তত 8% একটি একক ডিভাইস মডেলের জন্য ব্যবহারকারী-অনুভূত ANR অনুভব করে।

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

যখন আপনার অ্যাপ অতিরিক্ত ANR প্রদর্শন করছে তখন Android ভাইটাল আপনাকে প্লে কনসোলের মাধ্যমে সতর্ক করতে পারে।

Google Play কীভাবে Android গুরুত্বপূর্ণ ডেটা সংগ্রহ করে সে সম্পর্কে তথ্যের জন্য, Play Console ডকুমেন্টেশন দেখুন।

ANR নির্ণয় করুন

ANR নির্ণয় করার সময় দেখার জন্য কিছু সাধারণ নিদর্শন রয়েছে:

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

নিম্নলিখিত কৌশলগুলি আপনাকে আপনার ANR-এর কারণ নির্ধারণে সাহায্য করতে পারে।

স্বাস্থ্য পরিসংখ্যান

HealthStats মোট ব্যবহারকারী এবং সিস্টেমের সময়, CPU সময়, নেটওয়ার্ক, রেডিও পরিসংখ্যান, স্ক্রীন অন/অফ টাইম এবং জেগে ওঠার অ্যালার্ম ক্যাপচার করে একটি অ্যাপ্লিকেশনের স্বাস্থ্য সম্পর্কে মেট্রিক্স প্রদান করে। এটি সামগ্রিক CPU ব্যবহার এবং ব্যাটারি নিষ্কাশন পরিমাপ করতে সাহায্য করতে পারে।

ডিবাগ

Debug অ্যাপ্লিকেশানগুলিতে জ্যাঙ্ক এবং ল্যাগ সনাক্ত করতে ট্রেসিং এবং বরাদ্দ গণনা সহ বিকাশের সময় অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলি পরিদর্শন করতে সহায়তা করে৷ আপনি রানটাইম এবং নেটিভ মেমরি কাউন্টার এবং মেমরি মেট্রিক্স পেতে Debug ব্যবহার করতে পারেন যা একটি নির্দিষ্ট প্রক্রিয়ার মেমরি পদচিহ্ন সনাক্ত করতে সাহায্য করতে পারে।

অ্যাপ্লিকেশন এক্সিট ইনফো

ApplicationExitInfo Android 11 (API লেভেল 30) বা উচ্চতর সংস্করণে উপলব্ধ, এবং অ্যাপ্লিকেশন প্রস্থান করার কারণ সম্পর্কে তথ্য প্রদান করে। এর মধ্যে রয়েছে ANR, কম মেমরি, অ্যাপ ক্র্যাশ, অত্যধিক CPU ব্যবহার, ব্যবহারকারীর বাধা, সিস্টেম বাধা বা রানটাইম অনুমতি পরিবর্তন।

কঠোর মোড

StrictMode ব্যবহার করে আপনি আপনার অ্যাপ তৈরি করার সময় প্রধান থ্রেডে দুর্ঘটনাজনিত I/O অপারেশন খুঁজে পেতে সাহায্য করে। আপনি অ্যাপ্লিকেশন বা কার্যকলাপ স্তরে StrictMode ব্যবহার করতে পারেন।

পটভূমি ANR ডায়ালগ সক্ষম করুন৷

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

ট্রেসভিউ

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

একটি ট্রেস ফাইল টানুন

Android যখন ANR অনুভব করে তখন তথ্য ট্রেস করে। পুরোনো OS রিলিজে, ডিভাইসে একটি একক /data/anr/traces.txt ফাইল থাকে। নতুন OS রিলিজে, একাধিক /data/anr/anr_* ফাইল রয়েছে। আপনি রুট হিসাবে Android ডিবাগ ব্রিজ (adb) ব্যবহার করে একটি ডিভাইস বা এমুলেটর থেকে ANR ট্রেস অ্যাক্সেস করতে পারেন:

adb root
adb shell ls /data/anr
adb pull /data/anr/<filename>

আপনি ডিভাইসে বাগ রিপোর্ট বিকাশকারী বিকল্পটি বা আপনার ডেভেলপমেন্ট মেশিনে adb bugreport কমান্ড ব্যবহার করে একটি শারীরিক ডিভাইস থেকে একটি বাগ রিপোর্ট ক্যাপচার করতে পারেন। আরও তথ্যের জন্য, ক্যাপচার দেখুন এবং বাগ রিপোর্ট পড়ুন

সমস্যাগুলো ঠিক করুন

আপনি সমস্যা চিহ্নিত করার পরে, আপনি সাধারণত পাওয়া সমস্যাগুলি সমাধান করতে এই বিভাগে টিপস ব্যবহার করতে পারেন।

মূল থ্রেডে ধীর কোড

আপনার কোডের সেই জায়গাগুলি চিহ্নিত করুন যেখানে অ্যাপের প্রধান থ্রেড 5 সেকেন্ডের বেশি সময় ধরে ব্যস্ত থাকে। আপনার অ্যাপে সন্দেহজনক ব্যবহারের ক্ষেত্রে দেখুন এবং ANR পুনরুত্পাদন করার চেষ্টা করুন।

উদাহরণস্বরূপ, চিত্র 2 একটি ট্রেসভিউ টাইমলাইন দেখায় যেখানে প্রধান থ্রেড 5 সেকেন্ডের বেশি সময় ধরে ব্যস্ত থাকে।

চিত্র 2. ট্রেসভিউ টাইমলাইন একটি ব্যস্ত প্রধান থ্রেড দেখাচ্ছে

চিত্র 2. ট্রেসভিউ টাইমলাইন একটি ব্যস্ত প্রধান থ্রেড দেখাচ্ছে

চিত্র 2 দেখায় যে বেশিরভাগ আপত্তিকর কোড onClick(View) হ্যান্ডলারে ঘটে, যেমনটি নিম্নলিখিত কোড উদাহরণে দেখানো হয়েছে:

কোটলিন

override fun onClick(v: View) {
    // This task runs on the main thread.
    BubbleSort.sort(data)
}

জাভা

@Override
public void onClick(View view) {
    // This task runs on the main thread.
    BubbleSort.sort(data);
}

এই ক্ষেত্রে, আপনার মূল থ্রেডে যে কাজটি চলে তা একটি কর্মী থ্রেডে সরানো উচিত। অ্যান্ড্রয়েড ফ্রেমওয়ার্কে এমন ক্লাস রয়েছে যা কাজটিকে একজন কর্মী থ্রেডে নিয়ে যেতে সাহায্য করতে পারে। আরও তথ্যের জন্য কর্মী থ্রেড দেখুন।

প্রধান থ্রেডে IO

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

IO অপারেশনের কিছু উদাহরণ হল নেটওয়ার্ক এবং স্টোরেজ অপারেশন। আরও তথ্যের জন্য, নেটওয়ার্ক ক্রিয়াকলাপ সম্পাদন করা এবং ডেটা সংরক্ষণ করা দেখুন।

লক বিরোধ

কিছু পরিস্থিতিতে, যে কাজটি ANR ঘটায় তা সরাসরি অ্যাপের মূল থ্রেডে চালানো হয় না। যদি কোনও ওয়ার্কার থ্রেড কোনও রিসোর্সে লক রাখে যা মূল থ্রেডের কাজ সম্পূর্ণ করার জন্য প্রয়োজন, তাহলে একটি ANR ঘটতে পারে।

উদাহরণস্বরূপ, চিত্র 3 একটি ট্রেসভিউ টাইমলাইন দেখায় যেখানে বেশিরভাগ কাজ একজন কর্মী থ্রেডে সঞ্চালিত হয়।

চিত্র 3. ট্রেসভিউ টাইমলাইন যা দেখায় যে কাজটি একজন কর্মী থ্রেডে সম্পাদিত হচ্ছে

চিত্র 3. ট্রেসভিউ টাইমলাইন যা দেখায় যে কাজটি একজন কর্মী থ্রেডে সম্পাদিত হচ্ছে

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

কিন্তু যদি মূল থ্রেড এক্সিকিউশন পুনরায় শুরু করতে না পারে, তাহলে এটি BLOCKED অবস্থায় থাকে এবং ইভেন্টে সাড়া দিতে পারে না। রাজ্যটি Android ডিভাইস মনিটরে মনিটর হিসাবে দেখায় বা অপেক্ষা করুন , যেমন চিত্র 5-এ দেখানো হয়েছে।

চিত্র 4. মনিটরের স্থিতিতে প্রধান থ্রেড

চিত্র 4. মনিটরের স্থিতিতে প্রধান থ্রেড

নিম্নলিখিত ট্রেসটি একটি অ্যাপের প্রধান থ্রেড দেখায় যা একটি সংস্থানের জন্য অপেক্ষা করে অবরুদ্ধ করা হয়েছে:

...
AsyncTask #2" prio=5 tid=18 Runnable
  | group="main" sCount=0 dsCount=0 obj=0x12c333a0 self=0x94c87100
  | sysTid=25287 nice=10 cgrp=default sched=0/0 handle=0x94b80920
  | state=R schedstat=( 0 0 0 ) utm=757 stm=0 core=3 HZ=100
  | stack=0x94a7e000-0x94a80000 stackSize=1038KB
  | held mutexes= "mutator lock"(shared held)
  at com.android.developer.anrsample.BubbleSort.sort(BubbleSort.java:8)
  at com.android.developer.anrsample.MainActivity$LockTask.doInBackground(MainActivity.java:147)
  - locked <0x083105ee> (a java.lang.Boolean)
  at com.android.developer.anrsample.MainActivity$LockTask.doInBackground(MainActivity.java:135)
  at android.os.AsyncTask$2.call(AsyncTask.java:305)
  at java.util.concurrent.FutureTask.run(FutureTask.java:237)
  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
  at java.lang.Thread.run(Thread.java:761)
...

ট্রেস পর্যালোচনা করা আপনাকে কোডটি সনাক্ত করতে সাহায্য করতে পারে যা মূল থ্রেডটিকে ব্লক করে। নিম্নলিখিত কোডটি লকটি ধরে রাখার জন্য দায়ী যা পূর্ববর্তী ট্রেসে মূল থ্রেডটিকে ব্লক করে:

কোটলিন

override fun onClick(v: View) {
    // The worker thread holds a lock on lockedResource
    LockTask().execute(data)

    synchronized(lockedResource) {
        // The main thread requires lockedResource here
        // but it has to wait until LockTask finishes using it.
    }
}

class LockTask : AsyncTask<Array<Int>, Int, Long>() {
    override fun doInBackground(vararg params: Array<Int>): Long? =
            synchronized(lockedResource) {
                // This is a long-running operation, which makes
                // the lock last for a long time
                BubbleSort.sort(params[0])
            }
}

জাভা

@Override
public void onClick(View v) {
    // The worker thread holds a lock on lockedResource
   new LockTask().execute(data);

   synchronized (lockedResource) {
       // The main thread requires lockedResource here
       // but it has to wait until LockTask finishes using it.
   }
}

public class LockTask extends AsyncTask<Integer[], Integer, Long> {
   @Override
   protected Long doInBackground(Integer[]... params) {
       synchronized (lockedResource) {
           // This is a long-running operation, which makes
           // the lock last for a long time
           BubbleSort.sort(params[0]);
       }
   }
}

আরেকটি উদাহরণ হল একটি অ্যাপের প্রধান থ্রেড যা একজন কর্মী থ্রেড থেকে ফলাফলের জন্য অপেক্ষা করছে, যেমনটি নিম্নলিখিত কোডে দেখানো হয়েছে। মনে রাখবেন wait() এবং notify() ব্যবহার করা Kotlin-এ একটি প্রস্তাবিত প্যাটার্ন নয়, যার একযোগে পরিচালনা করার নিজস্ব পদ্ধতি রয়েছে। Kotlin ব্যবহার করার সময়, আপনি যদি সম্ভব হয় Kotlin-নির্দিষ্ট প্রক্রিয়া ব্যবহার করা উচিত।

কোটলিন

fun onClick(v: View) {
    val lock = java.lang.Object()
    val waitTask = WaitTask(lock)
    synchronized(lock) {
        try {
            waitTask.execute(data)
            // Wait for this worker thread’s notification
            lock.wait()
        } catch (e: InterruptedException) {
        }
    }
}

internal class WaitTask(private val lock: java.lang.Object) : AsyncTask<Array<Int>, Int, Long>() {
    override fun doInBackground(vararg params: Array<Int>): Long? {
        synchronized(lock) {
            BubbleSort.sort(params[0])
            // Finished, notify the main thread
            lock.notify()
        }
    }
}

জাভা

public void onClick(View v) {
   WaitTask waitTask = new WaitTask();
   synchronized (waitTask) {
       try {
           waitTask.execute(data);
           // Wait for this worker thread’s notification
           waitTask.wait();
       } catch (InterruptedException e) {}
   }
}

class WaitTask extends AsyncTask<Integer[], Integer, Long> {
   @Override
   protected Long doInBackground(Integer[]... params) {
       synchronized (this) {
           BubbleSort.sort(params[0]);
           // Finished, notify the main thread
           notify();
       }
   }
}

আরও কিছু পরিস্থিতি রয়েছে যা মূল থ্রেডকে ব্লক করতে পারে, যার মধ্যে থ্রেডগুলি যেগুলি Lock , Semaphore , সেইসাথে একটি রিসোর্স পুল (যেমন ডাটাবেস সংযোগের পুল) বা অন্যান্য পারস্পরিক বর্জন (mutex) প্রক্রিয়া ব্যবহার করে।

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

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

অচলাবস্থা

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

ডেডলকগুলি কম্পিউটার বিজ্ঞানে একটি ভালভাবে অধ্যয়ন করা ঘটনা এবং সেখানে অচলাবস্থা প্রতিরোধ অ্যালগরিদম রয়েছে যা আপনি অচলাবস্থা এড়াতে ব্যবহার করতে পারেন।

আরও তথ্যের জন্য, উইকিপিডিয়ায় ডেডলক এবং ডেডলক প্রতিরোধ অ্যালগরিদম দেখুন।

ধীর সম্প্রচার রিসিভার

অ্যাপ্লিকেশানগুলি ব্রডকাস্ট রিসিভারগুলির মাধ্যমে সম্প্রচার বার্তাগুলিতে প্রতিক্রিয়া জানাতে পারে, যেমন বিমান মোড সক্ষম বা অক্ষম করা বা সংযোগের স্থিতিতে পরিবর্তন। একটি ANR ঘটে যখন একটি অ্যাপ সম্প্রচার বার্তা প্রক্রিয়া করতে খুব বেশি সময় নেয়।

নিম্নলিখিত ক্ষেত্রে একটি ANR ঘটে:

  • একটি ব্রডকাস্ট রিসিভার যথেষ্ট সময়ের মধ্যে তার onReceive() পদ্ধতিটি কার্যকর করা শেষ করেনি।
  • একটি ব্রডকাস্ট রিসিভার goAsync() কল করে এবং PendingResult অবজেক্টে finish() কল করতে ব্যর্থ হয়।

আপনার অ্যাপের শুধুমাত্র একটি BroadcastReceiver এর onReceive() পদ্ধতিতে সংক্ষিপ্ত অপারেশন করা উচিত। যাইহোক, যদি একটি সম্প্রচার বার্তার ফলে আপনার অ্যাপের আরও জটিল প্রক্রিয়াকরণের প্রয়োজন হয় তাহলে আপনার কাজটি একটি IntentService এ পিছিয়ে দেওয়া উচিত।

আপনার ব্রডকাস্ট রিসিভার অ্যাপের প্রধান থ্রেডে দীর্ঘ-চলমান ক্রিয়াকলাপগুলি সম্পাদন করে কিনা তা সনাক্ত করতে আপনি ট্রেসভিউ-এর মতো সরঞ্জামগুলি ব্যবহার করতে পারেন৷ উদাহরণস্বরূপ, চিত্র 6 একটি ব্রডকাস্ট রিসিভারের টাইমলাইন দেখায় যা প্রায় 100 সেকেন্ডের জন্য মূল থ্রেডে একটি বার্তা প্রক্রিয়া করে।

চিত্র 5. ট্রেসভিউ টাইমলাইন মূল থ্রেডে `BroadcastReceiver` কাজ দেখাচ্ছে

চিত্র 5. ট্রেসভিউ টাইমলাইন প্রধান থ্রেডে BroadcastReceiver কাজ দেখাচ্ছে

এই আচরণটি BroadcastReceiver এর onReceive() পদ্ধতিতে দীর্ঘ-চলমান ক্রিয়াকলাপ সম্পাদন করার কারণে হতে পারে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

কোটলিন

override fun onReceive(context: Context, intent: Intent) {
    // This is a long-running operation
    BubbleSort.sort(data)
}

জাভা

@Override
public void onReceive(Context context, Intent intent) {
    // This is a long-running operation
    BubbleSort.sort(data);
}

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

কোটলিন

override fun onReceive(context: Context, intent: Intent) {
    Intent(context, MyIntentService::class.java).also { intentService ->
        // The task now runs on a worker thread.
        context.startService(intentService)
    }
}

class MyIntentService : IntentService("MyIntentService") {
    override fun onHandleIntent(intent: Intent?) {
        BubbleSort.sort(data)
    }
}

জাভা

@Override
public void onReceive(Context context, Intent intent) {
    // The task now runs on a worker thread.
    Intent intentService = new Intent(context, MyIntentService.class);
    context.startService(intentService);
}

public class MyIntentService extends IntentService {
   @Override
   protected void onHandleIntent(@Nullable Intent intent) {
       BubbleSort.sort(data);
   }
}

IntentService ব্যবহার করার ফলে, দীর্ঘমেয়াদী অপারেশন মূল থ্রেডের পরিবর্তে একটি কর্মী থ্রেডে সম্পাদিত হয়। চিত্র 7 ট্রেসভিউ টাইমলাইনে কর্মী থ্রেডের জন্য স্থগিত কাজ দেখায়।

চিত্র 6. ট্রেসভিউ টাইমলাইন একটি কর্মী থ্রেডে প্রক্রিয়াকৃত সম্প্রচার বার্তা দেখাচ্ছে

চিত্র 6. ট্রেসভিউ টাইমলাইন একটি কর্মী থ্রেডে প্রক্রিয়াকৃত সম্প্রচার বার্তা দেখাচ্ছে

আপনার ব্রডকাস্ট রিসিভার সিস্টেমকে সংকেত দিতে goAsync() ব্যবহার করতে পারে যে বার্তাটি প্রক্রিয়া করতে আরও সময় লাগবে। যাইহোক, আপনার PendingResult অবজেক্টে finish() কল করা উচিত। নিম্নলিখিত উদাহরণটি দেখায় কিভাবে ফিনিশ() কে কল করতে হয় যাতে সিস্টেম ব্রডকাস্ট রিসিভারকে রিসাইকেল করতে দেয় এবং একটি ANR এড়াতে পারে:

কোটলিন

val pendingResult = goAsync()

object : AsyncTask<Array<Int>, Int, Long>() {
    override fun doInBackground(vararg params: Array<Int>): Long? {
        // This is a long-running operation
        BubbleSort.sort(params[0])
        pendingResult.finish()
        return 0L
    }
}.execute(data)

জাভা

final PendingResult pendingResult = goAsync();
new AsyncTask<Integer[], Integer, Long>() {
   @Override
   protected Long doInBackground(Integer[]... params) {
       // This is a long-running operation
       BubbleSort.sort(params[0]);
       pendingResult.finish();
   }
}.execute(data);

যাইহোক, একটি ধীর ব্রডকাস্ট রিসিভার থেকে কোডটি অন্য থ্রেডে নিয়ে যাওয়া এবং goAsync() ব্যবহার করলে ANR ঠিক হবে না যদি সম্প্রচারটি ব্যাকগ্রাউন্ডে থাকে। ANR সময়সীমা এখনও প্রযোজ্য।

গেম অ্যাক্টিভিটি

GameActivity লাইব্রেরি C বা C++ তে লেখা গেম এবং অ্যাপের ক্ষেত্রে ANR কমিয়েছে। আপনি যদি আপনার বিদ্যমান নেটিভ অ্যাক্টিভিটিকে GameActivity দিয়ে প্রতিস্থাপন করেন, তাহলে আপনি UI থ্রেড ব্লকিং কমাতে পারেন এবং কিছু ANR ঘটতে বাধা দিতে পারেন।

ANR সম্পর্কে আরও তথ্যের জন্য, আপনার অ্যাপকে প্রতিক্রিয়াশীল রাখা দেখুন। থ্রেড সম্পর্কে আরও তথ্যের জন্য, থ্রেডিং কর্মক্ষমতা দেখুন।

{% শব্দার্থে %} {% endverbatim %}
  • দ্রষ্টব্য: জাভাস্ক্রিপ্ট বন্ধ থাকলে লিঙ্ক টেক্সট প্রদর্শিত হয়
  • অত্যধিক জাগরণ
{% শব্দার্থে %}
{% endverbatim %}