এই বিভাগে দেখানো হয়েছে যে কীভাবে অ্যাপ্লিকেশন উত্তর দিচ্ছে না (ANR) সংক্রান্ত সমস্যা
ProfilingManager ডিবাগ করতে হয়, এর সাথে একটি ট্রেস করার উদাহরণও দেওয়া হয়েছে।
ANR সংগ্রহ করার জন্য অ্যাপ সেট-আপ করা
আপনার অ্যাপে ANR ট্রিগার সেট-আপ করে শুরু করুন:
public void addANRTrigger() { ProfilingManager profilingManager = getApplicationContext().getSystemService( ProfilingManager.class); List<ProfilingTrigger> triggers = new ArrayList<>(); ProfilingTrigger.Builder triggerBuilder = new ProfilingTrigger.Builder( ProfilingTrigger.TRIGGER_TYPE_ANR); triggers.add(triggerBuilder.build()); Executor mainExecutor = Executors.newSingleThreadExecutor(); Consumer<ProfilingResult> resultCallback = profilingResult -> { // Handle uploading trace to your back-end }; profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback); profilingManager.addProfilingTriggers(triggers); }
ANR ট্রেস ক্যাপচার ও আপলোড করার পরে, Perfetto UI-তে এটি খুলুন।
ট্রেস বিশ্লেষণ করা
যেহেতু ANR ট্রেস ট্রিগার করেছে, তাই আপনি জানেন যে সিস্টেমটি আপনার অ্যাপের মূল থ্রেডে প্রতিক্রিয়া না দেওয়ার ঘটনা শনাক্ত করলে ট্রেস শেষ হয়ে যায়। UI-এর মধ্যে যথাযথভাবে ট্যাগ করা আপনার অ্যাপের মূল থ্রেডে কীভাবে নেভিগেট করতে হয় তা ১ নম্বর ছবিতে দেখানো হয়েছে।
ট্রেসের শেষ, ANR-এর টাইমস্ট্যাম্পের সাথে মিলে যায়, যেমনটি ২ নম্বর ছবিতে দেখানো হয়েছে।
এছাড়াও, ANR হওয়ার সময় অ্যাপ যেসব অপারেশন চালাচ্ছিল, ট্রেস তা দেখায়।
বিশেষ করে, অ্যাপটি handleNetworkResponse ট্রেস স্লাইসে কোড রান করেছে। এই
স্লাইসটি MyApp:SubmitButton স্লাইসের মধ্যে ছিল। এটি ১.৪৮ সেকেন্ডের CPU
টাইম ব্যবহার করেছে (ছবি ৩)।
ডিবাগ করার জন্য ANR-এর সময় আপনি যদি শুধুমাত্র স্ট্যাক ট্রেসের উপর নির্ভর করেন, তাহলে
আপনি হয়ত ভুল করে ANR-এর সম্পূর্ণ কারণ হিসেবে সেই কোডকে চিহ্নিত করবেন যেটি
handleNetworkResponse ট্রেস স্লাইসের মধ্যে রান করছে এবং প্রোফাইল
রেকর্ড করা শেষ হওয়ার সময়ও শেষ হয়নি। তবে,
১.৪৮ সেকেন্ডে নিজে থেকে ANR ট্রিগার করা যায় না, যদিও এটি একটি
কঠিন অপারেশন। এই পদ্ধতির আগে কোন জিনিসটি মূল থ্রেডকে ব্লক করেছিল তা বুঝতে আপনাকে আরও আগের সময়
দেখতে হবে।
ANR-এর কারণ খোঁজার জন্য একটি স্টার্টিং পয়েন্ট পেতে, আমরা UI থ্রেড দ্বারা জেনারেট করা শেষ ফ্রেমের
পরে খোঁজা শুরু করি, যা Choreographer#doFrame 551275 স্লাইসের সাথে সম্পর্কিত এবং ANR-এ শেষ হওয়া MyApp:SubmitButton স্লাইস শুরু হওয়ার আগে
বিলম্বের কোনও বড় সোর্স নেই (ছবি ৪)।
ব্লকেজ বুঝতে, সম্পূর্ণ MyApp:SubmitButton
স্লাইস ভালোভাবে দেখতে জুম-আউট করুন। থ্রেড স্টেটে আপনি একটি গুরুত্বপূর্ণ বিবরণ লক্ষ্য করবেন, যেমন
ছবি ৪-এ দেখানো হয়েছে: থ্রেডটি ৭৫% সময় (৬.৭ সেকেন্ড) Sleeping স্টেটে
এবং শুধুমাত্র ২৪% সময় Running স্টেটে ছিল।
এটি থেকে বোঝা যায় যে ANR-এর মূল কারণ হল অপেক্ষা করা, গণনা করা নয়। প্যাটার্ন খুঁজে পেতে আলাদা আলাদা ঘুমের ঘটনা পরীক্ষা করুন।
প্রথম তিনটি ঘুমের বিরতি (ছবি ৬–৮) প্রায় একই রকম, প্রতিটি প্রায় ২ সেকেন্ড। চতুর্থ ঘুমের আউটলায়ার (ছবি ৯) হল ০.৭ সেকেন্ড। কম্পিউটিং এনভায়রনমেন্টে ঠিক ২ সেকেন্ডের সময়সীমা খুব কমই কাকতালীয় হয়। এর থেকে বোঝা যায় যে এটি কোনও প্রোগ্রাম করা টাইম-আউট, কোনও র্যান্ডম রিসোর্স কনটেনশন নয়। শেষবার স্লিপ হওয়ার কারণ হতে পারে যে থ্রেডটি তার অপেক্ষা শেষ করেছে কারণ যে অপারেশনের জন্য এটি অপেক্ষা করছিল সেটি সফল হয়েছে।
এই হাইপোথিসিস হল যে অ্যাপটি একাধিকবার ২ সেকেন্ডের ব্যবহারকারী-সংজ্ঞায়িত টাইম-আউট হিট করছিল এবং অবশেষে সফল হয়েছিল, যার ফলে ANR ট্রিগার করার জন্য যথেষ্ট বিলম্ব হয়েছিল।
এটি যাচাই করতে, MyApp:SubmitButton trace
বিভাগের সাথে যুক্ত কোডটি ভালোভাবে দেখুন:
private static final int NETWORK_TIMEOUT_MILLISECS = 2000; public void setupButtonCallback() { findViewById(R.id.submit).setOnClickListener(submitButtonView -> { Trace.beginSection("MyApp:SubmitButton"); onClickSubmit(); Trace.endSection(); }); } public void onClickSubmit() { prepareNetworkRequest(); boolean networkRequestSuccess = false; int maxAttempts = 10; while (!networkRequestSuccess && maxAttempts > 0) { networkRequestSuccess = performNetworkRequest(NETWORK_TIMEOUT_MILLISECS); maxAttempts--; } if (networkRequestSuccess) { handleNetworkResponse(); } } boolean performNetworkRequest(int timeoutMiliseconds) { // ... } void prepareNetworkRequest() { // ... } public void handleNetworkResponse() { Trace.beginSection("handleNetworkResponse"); // ... Trace.endSection(); }
কোডটি এই হাইপোথিসিস কনফার্ম করে। onClickSubmit পদ্ধতিটি UI থ্রেডে হার্ডকোড করা NETWORK_TIMEOUT_MILLISECS সহ একটি নেটওয়ার্ক
অনুরোধ কার্যকর করে, যার মান হল ২০০০মিলি সেকেন্ড।
গুরুত্বপূর্ণভাবে, এটি একটি while লুপের মধ্যে রান করে যা ১০ বার পর্যন্ত আবার চেষ্টা করে।
এই নির্দিষ্ট ট্রেসে, ব্যবহারকারীর নেটওয়ার্ক কানেক্টিভিটি সম্ভবত খারাপ ছিল। প্রথম
তিনটি চেষ্টা ব্যর্থ হয়েছে, যার ফলে তিনটি ২-সেকেন্ডের টাইম-আউট হয়েছে (মোট ৬ সেকেন্ড)।
চতুর্থবার চেষ্টা করার পরে ০.৭ সেকেন্ডে সফল হয়েছে, এর ফলে কোডটি
handleNetworkResponse-এ যেতে পেরেছে। তবে, জমা হওয়া অপেক্ষার সময় আগেই ANR ট্রিগার করেছে।
নেটওয়ার্ক-সম্পর্কিত অপারেশনগুলি যেগুলির লেটেন্সি আলাদা আলাদা হয় সেগুলিকে মূল থ্রেডে এক্সিকিউট না করে ব্যাকগ্রাউন্ড থ্রেডে রেখে এই ধরনের ANR এড়িয়ে চলুন। এর ফলে, কানেক্টিভিটি খারাপ হলেও UI রেসপন্সিভ থাকে এবং এই ধরনের ANR সম্পূর্ণভাবে বন্ধ হয়ে যায়।