बैकग्राउंड में चल रही प्रोसेस, ज़्यादा मेमोरी और बैटरी खर्च कर सकती हैं. उदाहरण के लिए, इंप्लिसिट ब्रॉडकास्ट, बैकग्राउंड में चल रही ऐसी कई प्रोसेस शुरू कर सकता है जो इसे सुनने के लिए रजिस्टर की गई हैं. भले ही, उन प्रोसेस से ज़्यादा काम न हो. इससे डिवाइस की परफ़ॉर्मेंस और उपयोगकर्ता अनुभव पर काफ़ी असर पड़ सकता है.
इस समस्या को कम करने के लिए, Android 7.0 (एपीआई लेवल 24) में ये पाबंदियां लागू की गई हैं:
- Android 7.0 (एपीआई लेवल 24) और इसके बाद के वर्शन को टारगेट करने वाले ऐप्लिकेशन को
CONNECTIVITY_ACTIONब्रॉडकास्ट नहीं मिलते. ऐसा तब होता है, जब वे मेनिफ़ेस्ट में अपने ब्रॉडकास्ट रिसीवर का एलान करते हैं. ऐप्लिकेशन को अब भीCONNECTIVITY_ACTIONब्रॉडकास्ट मिलेंगे. इसके लिए, उन्हेंContext.registerReceiver()के साथBroadcastReceiverको रजिस्टर करना होगा. साथ ही, यह ज़रूरी है कि वह कॉन्टेक्स्ट अब भी मान्य हो. - ऐप्लिकेशन,
ACTION_NEW_PICTUREयाACTION_NEW_VIDEOब्रॉडकास्ट नहीं भेज सकते या उन्हें रिसीव नहीं कर सकते. इस ऑप्टिमाइज़ेशन का असर सभी ऐप्लिकेशन पर पड़ता है, न कि सिर्फ़ Android 7.0 (एपीआई लेवल 24) को टारगेट करने वाले ऐप्लिकेशन पर.
अगर आपका ऐप्लिकेशन इनमें से किसी भी इंटेंट का इस्तेमाल करता है, तो आपको उन पर निर्भरता को जल्द से जल्द हटाना चाहिए. इससे, Android 7.0 या इसके बाद के वर्शन वाले टारगेट डिवाइसों को सही तरीके से टारगेट किया जा सकेगा. Android फ़्रेमवर्क, इन इंप्लिसिट ब्रॉडकास्ट की ज़रूरत को कम करने के लिए कई समाधान उपलब्ध कराता है. उदाहरण के लिए, JobScheduler और नया WorkManager, नेटवर्क से जुड़े कामों को शेड्यूल करने के लिए बेहतर तरीके उपलब्ध कराते हैं. ऐसा तब होता है, जब तय की गई शर्तें पूरी होती हैं. जैसे, डेटा इस्तेमाल की सीमा न होने वाले नेटवर्क से कनेक्शन. अब JobScheduler का इस्तेमाल करके, कॉन्टेंट देने वाले ऐप्लिकेशन में हुए बदलावों पर प्रतिक्रिया दी जा सकती है. JobInfo
ऑब्जेक्ट, उन पैरामीटर को एनकैप्सुलेट करते हैं जिनका इस्तेमाल JobScheduler
आपके काम को शेड्यूल करने के लिए करता है. जब जॉब की शर्तें पूरी हो जाती हैं, तो सिस्टम आपके ऐप्लिकेशन के JobService पर इस जॉब को लागू करता है.
इस पेज पर, हम JobScheduler जैसे अन्य तरीकों का इस्तेमाल करना सीखेंगे, ताकि आपके ऐप्लिकेशन को इन नई पाबंदियों के हिसाब से ढाला जा सके.
उपयोगकर्ता की ओर से लगाई गई पाबंदियां
सिस्टम की सेटिंग में मौजूद बैटरी खर्च पेज पर, उपयोगकर्ता इनमें से कोई विकल्प चुन सकता है:
- कोई पाबंदी नहीं है: बैकग्राउंड में सभी काम करने की अनुमति दें. इससे ज़्यादा बैटरी खर्च हो सकती है.
- ऑप्टिमाइज़ किया गया (डिफ़ॉल्ट): यह सेटिंग, बैकग्राउंड में काम करने की ऐप्लिकेशन की क्षमता को ऑप्टिमाइज़ करती है. यह इस बात पर निर्भर करता है कि उपयोगकर्ता, ऐप्लिकेशन के साथ कैसे इंटरैक्ट करता है.
- पाबंदी लगी है: किसी ऐप्लिकेशन को बैकग्राउंड में चलने से पूरी तरह रोकता है. शायद ऐप्लिकेशन ठीक से काम न करें.
अगर कोई ऐप्लिकेशन, Android की ज़रूरी जानकारी में बताई गई कुछ खराब परफ़ॉर्मेंस दिखाता है, तो सिस्टम उपयोगकर्ता को उस ऐप्लिकेशन के लिए सिस्टम के संसाधनों का ऐक्सेस सीमित करने के लिए कह सकता है.
अगर सिस्टम को पता चलता है कि कोई ऐप्लिकेशन बहुत ज़्यादा संसाधनों का इस्तेमाल कर रहा है, तो वह उपयोगकर्ता को इसकी सूचना देता है. साथ ही, उपयोगकर्ता को ऐप्लिकेशन की कार्रवाइयों पर पाबंदी लगाने का विकल्प देता है. इन गतिविधियों की वजह से, सूचना ट्रिगर हो सकती है:
- वेक लॉक का बहुत ज़्यादा इस्तेमाल: स्क्रीन बंद होने पर, एक घंटे तक एक पार्शियल वेक लॉक का इस्तेमाल किया गया
- बैकग्राउंड में चलने वाली बहुत ज़्यादा सेवाएं: अगर ऐप्लिकेशन, 26 से कम एपीआई लेवल को टारगेट करता है और उसमें बैकग्राउंड में चलने वाली बहुत ज़्यादा सेवाएं हैं
डिवाइस बनाने वाली कंपनी यह तय करती है कि डिवाइस पर कौनसी पाबंदियां लगाई जाएं. उदाहरण के लिए, Android 9 (एपीआई लेवल 28) या इसके बाद के वर्शन पर काम करने वाले एओएसपी बिल्ड पर, बैकग्राउंड में चल रहे ऐसे ऐप्लिकेशन जो "प्रतिबंधित" स्थिति में हैं उन पर ये सीमाएं लागू होती हैं:
- फ़ोरग्राउंड सेवाएं लॉन्च नहीं की जा सकतीं
- मौजूदा फ़ोरग्राउंड सेवाओं को फ़ोरग्राउंड से हटा दिया जाता है
- अलार्म ट्रिगर नहीं होते
- जॉब पूरे नहीं हुए
इसके अलावा, अगर कोई ऐप्लिकेशन Android 13 (एपीआई लेवल 33) या इसके बाद के वर्शन को टारगेट करता है और "प्रतिबंधित" स्थिति में है, तो सिस्टम BOOT_COMPLETED ब्रॉडकास्ट या LOCKED_BOOT_COMPLETED ब्रॉडकास्ट तब तक डिलीवर नहीं करता, जब तक कि ऐप्लिकेशन को अन्य वजहों से शुरू न किया जाए.
पावर मैनेजमेंट से जुड़ी पाबंदियों में, खास पाबंदियों की जानकारी दी गई है.
नेटवर्क पर की जाने वाली गतिविधि के ब्रॉडकास्ट पाने पर पाबंदियां
Android 7.0 (एपीआई लेवल 24) को टारगेट करने वाले ऐप्लिकेशन को CONNECTIVITY_ACTION ब्रॉडकास्ट नहीं मिलते. ऐसा तब होता है, जब वे अपने मेनिफ़ेस्ट में उन्हें पाने के लिए रजिस्टर करते हैं. साथ ही, इस ब्रॉडकास्ट पर निर्भर प्रोसेस शुरू नहीं होंगी. इससे उन ऐप्लिकेशन के लिए समस्या हो सकती है जो नेटवर्क में होने वाले बदलावों को सुनना चाहते हैं या डिवाइस के किसी ऐसे नेटवर्क से कनेक्ट होने पर, नेटवर्क पर की जाने वाली कई गतिविधियां एक साथ करना चाहते हैं जिसके लिए डेटा इस्तेमाल की कोई सीमा नहीं है. इस पाबंदी से बचने के लिए, Android फ़्रेमवर्क में पहले से ही कई समाधान मौजूद हैं. हालांकि, सही समाधान चुनना इस बात पर निर्भर करता है कि आपको अपने ऐप्लिकेशन से क्या हासिल करना है.
ध्यान दें: BroadcastReceiver के साथ रजिस्टर किया गया Context.registerReceiver(), ऐप्लिकेशन के चलने के दौरान ये ब्रॉडकास्ट मैसेज पाना जारी रखता है.
ऐसे कनेक्शन पर नेटवर्क जॉब शेड्यूल करना जिन पर डेटा इस्तेमाल करने की कोई सीमा न हो
JobInfo ऑब्जेक्ट बनाने के लिए, JobInfo.Builder क्लास का इस्तेमाल करते समय, setRequiredNetworkType() तरीके को लागू करें और JobInfo.NETWORK_TYPE_UNMETERED को जॉब पैरामीटर के तौर पर पास करें. यहां दिए गए कोड सैंपल में, किसी सेवा को तब चलाने के लिए शेड्यूल किया गया है, जब डिवाइस को ऐसे नेटवर्क से कनेक्ट किया जाता है जिसमें डेटा इस्तेमाल की कोई सीमा नहीं है और डिवाइस चार्ज हो रहा है:
Kotlin
const val MY_BACKGROUND_JOB = 0 ... fun scheduleJob(context: Context) { val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler val job = JobInfo.Builder( MY_BACKGROUND_JOB, ComponentName(context, MyJobService::class.java) ) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true) .build() jobScheduler.schedule(job) }
Java
public static final int MY_BACKGROUND_JOB = 0; ... public static void scheduleJob(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo job = new JobInfo.Builder( MY_BACKGROUND_JOB, new ComponentName(context, MyJobService.class)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true) .build(); js.schedule(job); }
जब आपके जॉब की शर्तें पूरी हो जाती हैं, तो आपके ऐप्लिकेशन को तय किए गए JobService.class में onStartJob() तरीके को चलाने के लिए कॉलबैक मिलता है. JobScheduler को लागू करने के और उदाहरण देखने के लिए, JobScheduler का सैंपल ऐप्लिकेशन देखें.
JobScheduler का एक नया विकल्प WorkManager है. यह एक ऐसा एपीआई है जो आपको बैकग्राउंड में होने वाले ऐसे टास्क शेड्यूल करने की सुविधा देता है जिन्हें पूरा करना ज़रूरी है. भले ही, ऐप्लिकेशन प्रोसेस चल रही हो या नहीं. WorkManager, काम को चलाने का सही तरीका चुनता है. इसके लिए, वह आपके ऐप्लिकेशन प्रोसेस में सीधे थ्रेड पर काम करता है. साथ ही, डिवाइस के एपीआई लेवल जैसे फ़ैक्टर के आधार पर, JobScheduler, FirebaseJobDispatcher या AlarmManager का इस्तेमाल करता है. इसके अलावा, WorkManager को Play सेवाओं की ज़रूरत नहीं होती. यह कई ऐडवांस सुविधाएं देता है. जैसे, टास्क को एक साथ जोड़ना या किसी टास्क की स्थिति देखना. ज़्यादा जानने के लिए, WorkManager देखें.
ऐप्लिकेशन के चलने के दौरान, इंटरनेट कनेक्टिविटी को मॉनिटर करना
बैकग्राउंड में चल रहे ऐप्लिकेशन, रजिस्टर किए गए BroadcastReceiver की मदद से, अब भी CONNECTIVITY_CHANGE को सुन सकते हैं. हालांकि, ConnectivityManager एपीआई, कॉलबैक का अनुरोध करने के लिए ज़्यादा बेहतर तरीका उपलब्ध कराता है. यह अनुरोध सिर्फ़ तब किया जाता है, जब नेटवर्क की तय की गई शर्तें पूरी होती हैं.
NetworkRequest ऑब्जेक्ट, NetworkCapabilities के हिसाब से नेटवर्क कॉलबैक के पैरामीटर तय करते हैं. NetworkRequest.Builder क्लास की मदद से, NetworkRequest ऑब्जेक्ट बनाए जाते हैं. registerNetworkCallback()
इसके बाद, सिस्टम को NetworkRequest ऑब्जेक्ट पास करता है. नेटवर्क की शर्तें पूरी होने पर, ऐप्लिकेशन को अपनी ConnectivityManager.NetworkCallback क्लास में तय किए गए onAvailable() तरीके को लागू करने के लिए कॉलबैक मिलता है.
ऐप्लिकेशन को तब तक कॉलबैक मिलते रहते हैं, जब तक कि ऐप्लिकेशन बंद नहीं हो जाता या वह unregisterNetworkCallback() को कॉल नहीं करता.
इमेज और वीडियो ब्रॉडकास्ट पाने से जुड़ी पाबंदियां
Android 7.0 (एपीआई लेवल 24) में, ऐप्लिकेशन ACTION_NEW_PICTURE या ACTION_NEW_VIDEO ब्रॉडकास्ट नहीं भेज सकते या उन्हें नहीं पा सकते. इस पाबंदी से, परफ़ॉर्मेंस और उपयोगकर्ता अनुभव पर पड़ने वाले असर को कम करने में मदद मिलती है. ऐसा तब होता है, जब किसी नई इमेज या वीडियो को प्रोसेस करने के लिए, कई ऐप्लिकेशन को चालू करना पड़ता है. Android 7.0 (एपीआई लेवल 24) में, JobInfo और JobParameters को एक्सटेंड किया गया है, ताकि एक वैकल्पिक समाधान उपलब्ध कराया जा सके.
कॉन्टेंट यूआरआई में बदलाव होने पर जॉब ट्रिगर करना
कॉन्टेंट यूआरआई में बदलाव होने पर जॉब ट्रिगर करने के लिए, Android 7.0 (एपीआई लेवल 24) में JobInfo एपीआई को इन तरीकों से बेहतर बनाया गया है:
-
JobInfo.TriggerContentUri() - कॉन्टेंट यूआरआई में बदलाव होने पर, किसी जॉब को ट्रिगर करने के लिए ज़रूरी पैरामीटर को एनकैप्सुलेट करता है.
-
JobInfo.Builder.addTriggerContentUri() -
JobInfoकोTriggerContentUriऑब्जेक्ट पास करता है.ContentObserver, एनकैप्सुलेट किए गए कॉन्टेंट यूआरआई को मॉनिटर करता है. अगर किसी जॉब से कईTriggerContentUriऑब्जेक्ट जुड़े हैं, तो सिस्टम कॉलबैक उपलब्ध कराता है. भले ही, वह सिर्फ़ एक कॉन्टेंट यूआरआई में बदलाव की रिपोर्ट करे. -
अगर दिए गए यूआरआई के किसी भी डिसेंडेंट में बदलाव होता है, तो जॉब को ट्रिगर करने के लिए,
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTSफ़्लैग जोड़ें. यह फ़्लैग,registerContentObserver()को पास किए गएnotifyForDescendantsपैरामीटर से मेल खाता है.
ध्यान दें: TriggerContentUri() का इस्तेमाल, setPeriodic() या setPersisted() के साथ नहीं किया जा सकता. कॉन्टेंट में होने वाले बदलावों पर लगातार नज़र रखने के लिए, ऐप्लिकेशन के JobService की ओर से सबसे हाल के कॉलबैक को मैनेज करने से पहले, एक नया JobInfo शेड्यूल करें.
यहां दिया गया सैंपल कोड, किसी जॉब को ट्रिगर करने के लिए शेड्यूल करता है. ऐसा तब होता है, जब सिस्टम कॉन्टेंट यूआरआई, MEDIA_URI में बदलाव की रिपोर्ट करता है:
Kotlin
const val MY_BACKGROUND_JOB = 0 ... fun scheduleJob(context: Context) { val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler val job = JobInfo.Builder( MY_BACKGROUND_JOB, ComponentName(context, MediaContentJob::class.java) ) .addTriggerContentUri( JobInfo.TriggerContentUri( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS ) ) .build() jobScheduler.schedule(job) }
Java
public static final int MY_BACKGROUND_JOB = 0; ... public static void scheduleJob(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo.Builder builder = new JobInfo.Builder( MY_BACKGROUND_JOB, new ComponentName(context, MediaContentJob.class)); builder.addTriggerContentUri( new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)); js.schedule(builder.build()); }
जब सिस्टम, बताए गए कॉन्टेंट यूआरआई में किसी बदलाव की रिपोर्ट करता है, तो आपके ऐप्लिकेशन को एक कॉलबैक मिलता है. साथ ही, JobParameters ऑब्जेक्ट को MediaContentJob.class में onStartJob() तरीके से पास किया जाता है.
यह पता लगाना कि किस कॉन्टेंट अथॉरिटी ने कोई जॉब ट्रिगर किया है
Android 7.0 (एपीआई लेवल 24) JobParameters को भी बेहतर बनाता है, ताकि आपके ऐप्लिकेशन को इस बारे में काम की जानकारी मिल सके कि किन कॉन्टेंट अथॉरिटी और यूआरआई ने जॉब को ट्रिगर किया:
-
Uri[] getTriggeredContentUris() -
यह यूआरआई का एक कलेक्शन दिखाता है, जिसने जॉब को ट्रिगर किया है. अगर किसी यूआरआई ने जॉब को ट्रिगर नहीं किया है (उदाहरण के लिए, जॉब को समयसीमा या किसी अन्य वजह से ट्रिगर किया गया था) या बदले गए यूआरआई की संख्या 50 से ज़्यादा है, तो यह
nullहोगा. -
String[] getTriggeredContentAuthorities() -
यह फ़ंक्शन, कॉन्टेंट अथॉरिटी का स्ट्रिंग अरे दिखाता है. इस स्ट्रिंग अरे में, उन कॉन्टेंट अथॉरिटी की जानकारी होती है जिन्होंने जॉब को ट्रिगर किया है.
अगर दिखाया गया कलेक्शन
nullनहीं है, तोgetTriggeredContentUris()का इस्तेमाल करके यह जानकारी पाएं कि कौनसे यूआरआई बदले गए हैं.
यहां दिया गया सैंपल कोड, JobService.onStartJob() तरीके को बदल देता है. साथ ही, उन कॉन्टेंट अथॉरिटी और यूआरआई को रिकॉर्ड करता है जिन्होंने जॉब को ट्रिगर किया है:
Kotlin
override fun onStartJob(params: JobParameters): Boolean { StringBuilder().apply { append("Media content has changed:\n") params.triggeredContentAuthorities?.also { authorities -> append("Authorities: ${authorities.joinToString(", ")}\n") append(params.triggeredContentUris?.joinToString("\n")) } ?: append("(No content)") Log.i(TAG, toString()) } return true }
Java
@Override public boolean onStartJob(JobParameters params) { StringBuilder sb = new StringBuilder(); sb.append("Media content has changed:\n"); if (params.getTriggeredContentAuthorities() != null) { sb.append("Authorities: "); boolean first = true; for (String auth : params.getTriggeredContentAuthorities()) { if (first) { first = false; } else { sb.append(", "); } sb.append(auth); } if (params.getTriggeredContentUris() != null) { for (Uri uri : params.getTriggeredContentUris()) { sb.append("\n"); sb.append(uri); } } } else { sb.append("(No content)"); } Log.i(TAG, sb.toString()); return true; }
अपने ऐप्लिकेशन को और ऑप्टिमाइज़ करना
कम मेमोरी वाले डिवाइसों या कम मेमोरी वाली स्थितियों में काम करने के लिए, अपने ऐप्लिकेशन को ऑप्टिमाइज़ करने से, परफ़ॉर्मेंस और उपयोगकर्ता अनुभव को बेहतर बनाया जा सकता है. बैकग्राउंड में चलने वाली सेवाओं और मेनिफ़ेस्ट में रजिस्टर किए गए इंप्लिसिट ब्रॉडकास्ट रिसीवर पर निर्भरता हटाने से, आपका ऐप्लिकेशन ऐसे डिवाइसों पर बेहतर तरीके से काम कर सकता है. हालांकि, Android 7.0 (एपीआई लेवल 24) में इनमें से कुछ समस्याओं को कम करने के लिए कदम उठाए गए हैं, लेकिन हमारा सुझाव है कि आप अपने ऐप्लिकेशन को इस तरह से ऑप्टिमाइज़ करें कि वह बैकग्राउंड में चल रही इन प्रोसेस का इस्तेमाल किए बिना ही काम करे.
Android डीबग ब्रिज (एडीबी) के इन कमांड की मदद से, बैकग्राउंड में चल रही प्रोसेस बंद होने पर ऐप्लिकेशन के काम करने के तरीके की जांच की जा सकती है:
- इंप्लिसिट ब्रॉडकास्ट और बैकग्राउंड में चलने वाली सेवाओं के उपलब्ध न होने की स्थितियों को सिम्युलेट करने के लिए, यह कमांड डालें:
-
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore - इंप्लिसिट ब्रॉडकास्ट और बैकग्राउंड में चलने वाली सेवाओं को फिर से चालू करने के लिए, यह कमांड डालें:
-
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow - आपके पास यह सिम्युलेट करने का विकल्प होता है कि उपयोगकर्ता ने आपके ऐप्लिकेशन को बैकग्राउंड में बैटरी के इस्तेमाल के लिए, "प्रतिबंधित" स्थिति में रखा है. इस सेटिंग की मदद से, आपके ऐप्लिकेशन को बैकग्राउंड में चलने से रोका जा सकता है. इसके लिए, टर्मिनल विंडो में यह कमांड चलाएं:
-
$ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny