ANR

जब किसी Android ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई) थ्रेड बहुत देर तक ब्लॉक रहता है, तो "ऐप्लिकेशन काम नहीं कर रहा है" (एएनआर) गड़बड़ी ट्रिगर होती है. अगर ऐप्लिकेशन फ़ोरग्राउंड में है, तो सिस्टम उपयोगकर्ता को एक डायलॉग दिखाता है. यह पहली इमेज में दिखाया गया है. एएनआर डायलॉग, उपयोगकर्ता को ऐप्लिकेशन को अभी बंद करने का विकल्प देता है.

उपयोगकर्ता को ANR डायलॉग दिखाया गया.
पहली इमेज. उपयोगकर्ता को ANR डायलॉग दिखाया गया

एएनआर की गड़बड़ियां एक समस्या हैं, क्योंकि ऐप्लिकेशन का मुख्य थ्रेड, यूज़र इंटरफ़ेस (यूआई) को अपडेट करने के लिए ज़िम्मेदार होता है. यह उपयोगकर्ता के इनपुट इवेंट को प्रोसेस नहीं कर सकता या ड्रॉ नहीं कर सकता. इससे उपयोगकर्ता को परेशानी होती है. ऐप्लिकेशन के मुख्य थ्रेड के बारे में ज़्यादा जानने के लिए, प्रोसेस और थ्रेड की खास जानकारी देखें.

आपके ऐप्लिकेशन के लिए एएनआर तब ट्रिगर होता है, जब इनमें से कोई एक स्थिति होती है:

  • इनपुट डिस्पैच करने की समयसीमा खत्म हो गई है: अगर आपके ऐप्लिकेशन ने पांच सेकंड के अंदर, इनपुट इवेंट (जैसे, बटन दबाना या स्क्रीन को छूना) का जवाब नहीं दिया है.
  • सेवा को लागू करना: अगर आपके ऐप्लिकेशन की ओर से बताई गई कोई सेवा, Service.onCreate और Service.onStartCommand/Service.onBind को कुछ सेकंड में लागू नहीं कर पाती है.
  • Service.startForeground को कॉल नहीं किया गया: अगर आपका ऐप्लिकेशन फ़ोरग्राउंड में नई सेवा शुरू करने के लिए Context.startForegroundService का इस्तेमाल करता है, लेकिन सेवा पांच सेकंड के अंदर startForeground को कॉल नहीं करती है.
  • ब्रॉडकास्ट ऑफ़ इंटेंट: अगर कोई BroadcastReceiver तय समय में पूरा नहीं होता है. अगर ऐप्लिकेशन में फ़ोरग्राउंड में कोई गतिविधि हो रही है, तो टाइम आउट 10 सेकंड का होता है.
  • JobScheduler इंटरैक्शन: अगर JobService, JobService.onStartJob या JobService.onStopJob से कुछ सेकंड के अंदर वापस नहीं आता है या अगर उपयोगकर्ता की ओर से शुरू किया गया कोई जॉब शुरू होता है और आपका ऐप्लिकेशन, JobService.onStartJob को कॉल करने के कुछ सेकंड के अंदर JobService.setNotification को कॉल नहीं करता है. Android 13 और इससे पहले के वर्शन को टारगेट करने वाले ऐप्लिकेशन के लिए, एएनआर की गड़बड़ियां साइलेंट होती हैं और ऐप्लिकेशन को इनकी जानकारी नहीं दी जाती. Android 14 और इसके बाद के वर्शन को टारगेट करने वाले ऐप्लिकेशन के लिए, एएनआर की गड़बड़ियां साफ़ तौर पर दिखती हैं और ऐप्लिकेशन को इनकी जानकारी दी जाती है.

अगर आपके ऐप्लिकेशन में एएनआर की समस्या आ रही है, तो इस दस्तावेज़ में दिए गए दिशा-निर्देशों का इस्तेमाल करके, समस्या का विश्लेषण किया जा सकता है और उसे ठीक किया जा सकता है.

एएनआर की गड़बड़ियों का विश्लेषण करना

एएनआर की गड़बड़ियों का पता लगाते समय, कुछ सामान्य पैटर्न पर ध्यान देना चाहिए:

  • ऐप्लिकेशन, मुख्य थ्रेड पर I/O से जुड़ी धीमी कार्रवाइयां कर रहा है.
  • ऐप्लिकेशन, मुख्य थ्रेड पर लंबे समय से कैलकुलेशन कर रहा है.
  • मुख्य थ्रेड, किसी दूसरी प्रोसेस के लिए सिंक्रोनस बाइंडर कॉल कर रहा है. साथ ही, उस दूसरी प्रोसेस को पूरा होने में ज़्यादा समय लग रहा है.
  • मुख्य थ्रेड को ब्लॉक किया गया है. यह किसी दूसरे थ्रेड पर चल रहे लंबे ऑपरेशन के लिए, सिंक्रनाइज़ किए गए ब्लॉक का इंतज़ार कर रही है.
  • मुख्य थ्रेड, आपकी प्रोसेस में या बाइंडर कॉल के ज़रिए किसी दूसरी थ्रेड के साथ डेडलॉक में है. मुख्य थ्रेड, किसी लंबे ऑपरेशन के खत्म होने का इंतज़ार नहीं कर रही है, बल्कि डेडलॉक की स्थिति में है.

इन तरीकों से, एएनआर की वजह का पता लगाया जा सकता है.

HealthStats

HealthStats, किसी ऐप्लिकेशन की परफ़ॉर्मेंस से जुड़ी मेट्रिक उपलब्ध कराता है. इसके लिए, यह उपयोगकर्ता और सिस्टम के कुल समय, सीपीयू समय, नेटवर्क, रेडियो के आंकड़े, स्क्रीन चालू/बंद होने का समय, और वेक अप अलार्म को कैप्चर करता है. इससे आपको सीपीयू के कुल इस्तेमाल और बैटरी खर्च होने की दर को मेज़र करने में मदद मिल सकती है.

डीबग

Debug की मदद से, Android ऐप्लिकेशन को डेवलप करने के दौरान उनकी जांच की जा सकती है. इसमें ऐप्लिकेशन में होने वाली रुकावटों और लैग की पहचान करने के लिए, ट्रेसिंग और ऐलोकेशन की संख्या शामिल है. Debug का इस्तेमाल करके, रनटाइम और नेटिव मेमोरी काउंटर के साथ-साथ मेमोरी मेट्रिक भी देखी जा सकती हैं. इनसे आपको किसी प्रोसेस के लिए इस्तेमाल की जाने वाली मेमोरी (मेमोरी फ़ुटप्रिंट) का पता लगाने में मदद मिल सकती है.

ApplicationExitInfo

ApplicationExitInfo, Android 11 (एपीआई लेवल 30) या इसके बाद के वर्शन पर उपलब्ध है. इससे ऐप्लिकेशन के बंद होने की वजह के बारे में जानकारी मिलती है. इसमें ANR, कम मेमोरी, ऐप्लिकेशन क्रैश होना, सीपीयू का ज़्यादा इस्तेमाल, उपयोगकर्ता की वजह से होने वाली रुकावटें, सिस्टम की वजह से होने वाली रुकावटें, और रनटाइम की अनुमति में होने वाले बदलाव शामिल हैं.

स्ट्रिक्ट मोड

StrictMode का इस्तेमाल करके, ऐप्लिकेशन डेवलप करते समय मुख्य थ्रेड पर अनचाहे I/O ऑपरेशन का पता लगाया जा सकता है. StrictMode का इस्तेमाल, ऐप्लिकेशन या गतिविधि के लेवल पर किया जा सकता है.

बैकग्राउंड में एएनआर डायलॉग चालू करना

Android, उन ऐप्लिकेशन के लिए एएनआर डायलॉग दिखाता है जो ब्रॉडकास्ट मैसेज को प्रोसेस करने में ज़्यादा समय लेते हैं. हालांकि, ऐसा सिर्फ़ तब होता है, जब डिवाइस के डेवलपर के लिए सेटिंग और टूल में जाकर, सभी एएनआर दिखाएं को चालू किया गया हो. इस वजह से, बैकग्राउंड में ANR की गड़बड़ी होने पर, उपयोगकर्ता को हमेशा डायलॉग बॉक्स नहीं दिखता. भले ही, ऐप्लिकेशन की परफ़ॉर्मेंस में समस्याएं आ रही हों.

रीकंपोज़िशन से जुड़ी समस्याएं

फिर से कॉम्पोज़ करने में आने वाली रुकावटों को ट्रैक करने के लिए, Android Studio प्रोफ़ाइलर और लेआउट इंस्पेक्टर का इस्तेमाल करें. ज़्यादा जानकारी के लिए, Jetpack Compose की परफ़ॉर्मेंस देखें.

ट्रेस फ़ाइल को पुल करना

जब Android को एएनआर की समस्या का सामना करना पड़ता है, तो वह ट्रेस की जानकारी सेव करता है. ओएस के पुराने वर्शन वाले डिवाइसों पर, सिर्फ़ एक /data/anr/traces.txt फ़ाइल होती है. ओएस के नए वर्शन में, एक से ज़्यादा /data/anr/anr_* फ़ाइलें होती हैं. रूट के तौर पर Android डीबग ब्रिज (एडीबी) का इस्तेमाल करके, किसी डिवाइस या एम्युलेटर से एएनआर ट्रेस ऐक्सेस किए जा सकते हैं:

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

किसी फ़िज़िकल डिवाइस से गड़बड़ी की रिपोर्ट कैप्चर की जा सकती है. इसके लिए, डिवाइस पर 'गड़बड़ी की रिपोर्ट पाएं' डेवलपर विकल्प या अपनी डेवलपमेंट मशीन पर adb bugreport कमांड का इस्तेमाल करें. ज़्यादा जानकारी के लिए, गड़बड़ी की रिपोर्ट कैप्चर करना और पढ़ना लेख पढ़ें.

समस्याएं ठीक करना

समस्या का पता चलने के बाद, इस सेक्शन में दी गई सलाह का इस्तेमाल करके, आम तौर पर होने वाली समस्याओं को ठीक किया जा सकता है.

मुख्य थ्रेड पर धीमा कोड

अपने कोड में उन जगहों की पहचान करें जहां ऐप्लिकेशन का मुख्य थ्रेड, पांच सेकंड से ज़्यादा समय तक व्यस्त रहता है. अपने ऐप्लिकेशन में संदिग्ध इस्तेमाल के उदाहरण देखें और एएनआर को फिर से जनरेट करने की कोशिश करें.

एक आम समस्या यह है कि कंपोज़ेबल में सीधे तौर पर लंबे समय तक चलने वाला टास्क मौजूद होता है:

@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 या डेटाबेस कॉल) को ट्रिगर कर देते हैं.

ज़्यादा समय तक चलने वाली I/O कार्रवाइयों को यूज़र इंटरफ़ेस (यूआई) लेयर से दूर रखें. withContext(Dispatchers.IO) का इस्तेमाल ViewModel में करें या इससे भी बेहतर होगा कि डेटा लेयर पर Repository का इस्तेमाल करें.

डेडलॉक

डेडलॉक तब होता है, जब कोई थ्रेड इंतज़ार की स्थिति में चला जाता है. ऐसा इसलिए होता है, क्योंकि ज़रूरी संसाधन किसी दूसरे थ्रेड के पास होता है. यह थ्रेड भी पहले थ्रेड के पास मौजूद संसाधन का इंतज़ार कर रहा होता है. अगर ऐप्लिकेशन का मुख्य थ्रेड इस स्थिति में है, तो ANR की गड़बड़ियां होने की संभावना है.

कंप्यूटर साइंस में डेडलॉक के बारे में काफ़ी रिसर्च की गई है. डेडलॉक से बचने के लिए, डेडलॉक की रोकथाम करने वाले एल्गोरिदम मौजूद हैं. इनका इस्तेमाल करके डेडलॉक से बचा जा सकता है.

ज़्यादा जानकारी के लिए, Wikipedia पर डेडलॉक और डेडलॉक को रोकने वाले एल्गोरिदम लेख पढ़ें.

Kotlin और Compose का इस्तेमाल करते समय, प्रिमिटिव लॉक को नॉन-ब्लॉकिंग कोरूटीन Mutexes (Mutex.withLock) से बदला जा सकता है. इससे यूज़र इंटरफ़ेस (यूआई) थ्रेड को फ़्रीज़ करने के बजाय, एक्ज़ीक्यूशन कॉन्टेक्स्ट को निलंबित करके, थ्रेड को ब्लॉक होने से रोका जा सकता है. उदाहरण के लिए:

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()
        }
    }
}

धीमे ब्रॉडकास्ट रिसीवर

ऐप्लिकेशन, ब्रॉडकास्ट रिसीवर की मदद से ब्रॉडकास्ट मैसेज का जवाब दे सकते हैं. जैसे, फ़्लाइट मोड को चालू या बंद करना या कनेक्टिविटी की स्थिति में बदलाव करना. एएनआर तब होता है, जब कोई ऐप्लिकेशन ब्रॉडकास्ट मैसेज को प्रोसेस करने में बहुत ज़्यादा समय लेता है.

एएनआर की गड़बड़ी इन मामलों में होती है:

  • ब्रॉडकास्ट रिसीवर ने तय समय में onReceive तरीके को लागू नहीं किया.
  • कोई ब्रॉडकास्ट रिसीवर, goAsync को कॉल करता है और PendingResult ऑब्जेक्ट पर finish को कॉल नहीं कर पाता.

आपके ऐप्लिकेशन को BroadcastReceiver के onReceive तरीके में, सिर्फ़ छोटे ऑपरेशन करने चाहिए. हालांकि, अगर आपके ऐप्लिकेशन को ब्रॉडकास्ट मैसेज की वजह से ज़्यादा जटिल प्रोसेसिंग की ज़रूरत है, तो आपको टास्क को ViewModel (Kotlin कोरूटीन, स्कोप, और डिस्पैचर की मदद से) पर टाल देना चाहिए. ऐसा तब करना चाहिए, जब टास्क को पूरा होने में कुछ सेकंड लगने की उम्मीद हो. इसके अलावा, अगर टास्क को पूरा होने में कुछ सेकंड से ज़्यादा समय लगने की उम्मीद हो, तो उसे किसी भी तरह के स्टेट होल्डर या WorkManager पर टाल देना चाहिए.

GameActivity

GameActivity लाइब्रेरी ने C या C++ में लिखे गए गेम और ऐप्लिकेशन की केस स्टडी में, ANR की संख्या कम कर दी है. अगर अपनी मौजूदा नेटिव गतिविधि को GameActivity से बदल दिया जाए, तो यूज़र इंटरफ़ेस (यूआई) थ्रेड को ब्लॉक होने से रोका जा सकता है. साथ ही, कुछ ANR को होने से रोका जा सकता है.

एएनआर के बारे में ज़्यादा जानने के लिए, अपने ऐप्लिकेशन को रिस्पॉन्सिव बनाए रखना लेख पढ़ें. थ्रेड के बारे में ज़्यादा जानकारी के लिए, थ्रेड की मदद से बेहतर परफ़ॉर्मेंस लेख पढ़ें.

अन्य संसाधन

कॉन्टेंट देखना