ANRগুলি

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

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

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

নিম্নলিখিত কোনও একটি পরিস্থিতি দেখা দিলে আপনার অ্যাপের জন্য ANR ট্রিগার করা হয়:

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

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

ANR ডায়াগনসিস করা

ANR ডায়াগনসিস করার সময় কিছু সাধারণ প্যাটার্ন লক্ষ্য করতে হয়:

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

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

HealthStats

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

ডিবাগ করুন

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

ApplicationExitInfo

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

স্ট্রিক্ট মোড

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

ব্যাকগ্রাউন্ড ANR ডায়ালগ চালু করুন

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

রিকম্পোজিশন সংক্রান্ত সমস্যা

রিকম্পোজিশন সংক্রান্ত সমস্যা ট্র্যাক করতে Android Studio Profiler এবং লেআউট ইন্সপেক্টর ব্যবহার করুন। আরও তথ্যের জন্য, Jetpack Compose পারফর্ম্যান্স দেখুন।

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

ANR-এর অভিজ্ঞতা হলে Android ট্রেস তথ্য স্টোর করে। 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 কমান্ড ব্যবহার করে ফিজিক্যাল ডিভাইস থেকে ত্রুটির রিপোর্ট ক্যাপচার করতে পারবেন। আরও তথ্যের জন্য, ত্রুটির প্রতিবেদন ক্যাপচার করা ও পড়া দেখুন।

সমস্যার সমাধান করা

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

মূল থ্রেডে স্লো কোড

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

একটি সাধারণ সমস্যা হল সরাসরি কম্পোজেবলে দীর্ঘ সময় ধরে চলা টাস্ক:

@Composable
fun BadList(rawStrings: List<String>) {
    // Math or sorting inside the composable runs on EVERY recomposition pass!
    val heavilyProcessedList = rawStrings
        .filter { it.isNotBlank() }
        .map { it.uppercase().reversed() }
        .map { it.computationallyHeavyFunction() }
.sortedBy { it.length }
    LazyColumn { items(sortedList) { Text(it) } }
}

// Modern Compose-first fix
@Composable
fun GoodList(viewModel: MyViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    // UI simply renders state; no heavy processing allowed here
    LazyColumn { items(uiState.sortedData) { Text(it) } }
}

মূল থ্রেডে I/O

মূল থ্রেডে I/O অপারেশন এক্সিকিউট করা হল মূল থ্রেডে ধীরগতির অপারেশনের একটি সাধারণ কারণ, যা ANR-এর কারণ হতে পারে। Compose-এ, ডেভেলপাররা প্রায়ই প্রাথমিক অবস্থা পাওয়ার চেষ্টা করার সময় ভুলবশত ডিস্ক রিড (যেমন SharedPreferences বা ডেটাবেস কল) ট্রিগার করেন।

UI লেয়ার থেকে দূরে দীর্ঘ সময় ধরে চলা I/O অপারেশন এক্সিকিউট করুন। ViewModel-এ withContext(Dispatchers.IO) ব্যবহার করুন অথবা আরও ভাল হয় যদি ডেটা লেয়ারে Repository ব্যবহার করেন।

ডেডলক

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

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

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

Kotlin ও Compose ব্যবহার করার সময়, আপনি প্রিমিটিভ লককে নন-ব্লকিং কোরুটিন Mutexes (Mutex.withLock) দিয়ে প্রতিস্থাপন করতে পারেন যাতে UI থ্রেড ফ্রিজ করার পরিবর্তে এক্সিকিউশন কন্টেক্সট সাসপেন্ড করে থ্রেড ব্লকিং আটকানো যায়। যেমন:

import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

// Modern non-blocking concurrency state architecture
class SecureDataRepository {
    private val mutex = Mutex()

    suspend fun safeUIAccess() {
        // If locked, the main thread suspends seamlessly, preventing an ANR
        mutex.withLock {
            performSafeOperation()
        }
    }
}

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

অ্যাপগুলি ব্রডকাস্ট রিসিভারের মাধ্যমে ব্রডকাস্ট মেসেজের উত্তর দিতে পারে, যেমন বিমান মোড চালু বা বন্ধ করা বা কানেক্টিভিটি স্ট্যাটাসে পরিবর্তন করা। ব্রডকাস্ট মেসেজ প্রসেস করতে কোনও অ্যাপ অনেক বেশি সময় নিলে ANR হয়।

নিম্নলিখিত ক্ষেত্রে ANR হয়:

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

আপনার অ্যাপকে BroadcastReceiver-এর onReceive পদ্ধতিতে শুধুমাত্র ছোট অপারেশন সম্পাদন করতে হবে। তবে, ব্রডকাস্ট মেসেজের ফলে আপনার অ্যাপের আরও জটিল প্রসেসিংয়ের প্রয়োজন হলে, টাস্কটি সম্পূর্ণ করতে কয়েক সেকেন্ড সময় লাগলে, যেকোনও ধরনের স্টেট হোল্ডার বা ViewModel (Kotlin coroutines, scopes ও dispatchers-এর ক্ষমতা ব্যবহার করে) বা কয়েক সেকেন্ডের বেশি সময় লাগলে WorkManager-এ টাস্কটি পিছিয়ে দেওয়া উচিত।

GameActivity

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

ANR সম্পর্কে আরও তথ্যের জন্য, আপনার অ্যাপ রেসপন্সিভ রাখুন দেখুন। থ্রেড সম্পর্কে আরও তথ্য পেতে, থ্রেডিংয়ের মাধ্যমে আরও ভালো পারফর্ম্যান্স দেখুন।

অতিরিক্ত রিসোর্স

কন্টেন্ট দেখে