बैकग्राउंड में चलने वाली प्रोसेस, ज़्यादा मेमोरी और बैटरी इस्तेमाल कर सकती हैं. उदाहरण के लिए, किसी इंप्लिसिट ब्रॉडकास्ट की वजह से, बैकग्राउंड में कई प्रोसेस शुरू हो सकती हैं. भले ही, उन प्रोसेस से ज़्यादा काम न हो. ऐसा तब हो सकता है, जब उन प्रोसेस ने ब्रॉडकास्ट सुनने के लिए रजिस्टर किया हो. इससे डिवाइस की परफ़ॉर्मेंस और उपयोगकर्ता अनुभव, दोनों पर काफ़ी असर पड़ सकता है.
इस समस्या को कम करने के लिए, Android 7.0 (एपीआई लेवल 24) में ये पाबंदियां लागू की गई हैं:
- Android 7.0 (एपीआई लेवल 24) और उसके बाद के वर्शन को टारगेट करने वाले ऐप्लिकेशन को,
CONNECTIVITY_ACTIONब्रॉडकास्ट नहीं मिलते. ऐसा तब होता है, जब वे अपने मेनिफ़ेस्ट में ब्रॉडकास्ट रिसीवर की जानकारी देते हैं. अगर ऐप्लिकेशन,Context.registerReceiver()के साथ अपनाBroadcastReceiverरजिस्टर करते हैं और वह कॉन्टेक्स्ट अब भी मान्य है, तो उन्हेंCONNECTIVITY_ACTIONब्रॉडकास्ट मिलते रहेंगे. - ऐप्लिकेशन,
ACTION_NEW_PICTUREयाACTION_NEW_VIDEOब्रॉडकास्ट नहीं भेज सकते या पा नहीं सकते. इस ऑप्टिमाइज़ेशन का असर सभी ऐप्लिकेशन पर पड़ता है. सिर्फ़ उन ऐप्लिकेशन पर नहीं जो Android 7.0 (एपीआई लेवल 24) को टारगेट करते हैं.
अगर आपका ऐप्लिकेशन इनमें से किसी भी इंटेंट का इस्तेमाल करता है, तो आपको जल्द से जल्द उन पर से अपनी निर्भरता खत्म करनी चाहिए
इससे, Android 7.0
या उसके बाद के वर्शन वाले डिवाइसों को सही तरीके से टारगेट किया जा सकेगा. Android फ़्रेमवर्क, इन इंप्लिसिट ब्रॉडकास्ट की ज़रूरत को कम करने के लिए कई समाधान उपलब्ध कराता है. उदाहरण के लिए, JobScheduler और
नया WorkManager, नेटवर्क
ऑपरेशन शेड्यूल करने के लिए मज़बूत सिस्टम उपलब्ध कराते हैं. ऐसा तब होता है, जब तय की गई शर्तें पूरी होती हैं. जैसे, बिना शुल्क वाले
नेटवर्क से कनेक्शन. अब कॉन्टेंट प्रोवाइडर में होने वाले बदलावों पर प्रतिक्रिया देने के लिए भी JobScheduler
का इस्तेमाल किया जा सकता है. JobInfo
ऑब्जेक्ट में वे पैरामीटर शामिल होते हैं जिनका इस्तेमाल, JobScheduler
आपके जॉब को शेड्यूल करने के लिए करता है. जब जॉब की शर्तें पूरी हो जाती हैं, तो सिस्टम
आपके ऐप्लिकेशन के JobService पर इस जॉब को पूरा करता है.
इस पेज पर, हम
JobScheduler जैसे दूसरे तरीकों का इस्तेमाल करके, अपने ऐप्लिकेशन को इन नई
पाबंदियों के हिसाब से ढालने का तरीका जानेंगे.
उपयोगकर्ता की ओर से लगाई गई पाबंदियां
सिस्टम सेटिंग में मौजूद बैटरी का इस्तेमाल पेज पर, उपयोगकर्ता इनमें से कोई विकल्प चुन सकता है:
- कोई पाबंदी नहीं: बैकग्राउंड में सभी काम करने की अनुमति दें. इससे बैटरी ज़्यादा खर्च हो सकती है.
- ऑप्टिमाइज़ किया गया (डिफ़ॉल्ट): उपयोगकर्ता के ऐप्लिकेशन के साथ इंटरैक्ट करने के तरीके के आधार पर, बैकग्राउंड में काम करने की ऐप्लिकेशन की क्षमता को ऑप्टिमाइज़ करें.
- पाबंदी लगाई गई: किसी ऐप्लिकेशन को बैकग्राउंड में चलने से पूरी तरह से रोकें. ऐसा हो सकता है कि ऐप्लिकेशन ठीक से काम न करें.
अगर कोई ऐप्लिकेशन, Android vitals में बताए गए खराब व्यवहार दिखाता है, तो सिस्टम उपयोगकर्ता को उस ऐप्लिकेशन के सिस्टम रिसॉर्स के ऐक्सेस पर पाबंदी लगाने के लिए कह सकता है.
अगर सिस्टम को पता चलता है कि कोई ऐप्लिकेशन, ज़रूरत से ज़्यादा रिसॉर्स इस्तेमाल कर रहा है, तो वह उपयोगकर्ता को इसकी सूचना देता है है. साथ ही, उपयोगकर्ता को ऐप्लिकेशन की कार्रवाइयों पर पाबंदी लगाने का विकल्प देता है. इन वजहों से सूचना ट्रिगर हो सकती है:
- वेक लॉक का ज़्यादा इस्तेमाल: स्क्रीन बंद होने पर, एक घंटे के लिए पार्शियल वेक लॉक का इस्तेमाल
- बैकग्राउंड में ज़्यादा सेवाओं का इस्तेमाल: अगर ऐप्लिकेशन, एपीआई लेवल 26 से पहले के लेवल को टारगेट करता है और बैकग्राउंड में ज़्यादा सेवाओं का इस्तेमाल करता है
लगाई गई पाबंदियों के बारे में, डिवाइस बनाने वाली कंपनी तय करती है. उदाहरण के लिए, AOSP बिल्ड पर 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 का सैंपल ऐप्लिकेशन देखें.
WorkManager, JobScheduler का एक नया विकल्प है. यह एक एपीआई है, जिसकी मदद से बैकग्राउंड में ऐसे टास्क शेड्यूल किए जा सकते हैं जिन्हें पूरा करना ज़रूरी है. भले ही, ऐप्लिकेशन की प्रोसेस चल रही हो या नहीं. WorkManager डिवाइस के एपीआई लेवल जैसे फ़ैक्टर के आधार पर, काम करने का सही तरीका चुनता है. जैसे, सीधे आपके ऐप्लिकेशन की प्रोसेस में किसी थ्रेड पर, JobScheduler, FirebaseJobDispatcher या AlarmManager का इस्तेमाल करके. इसके अलावा, WorkManager के लिए Play services की ज़रूरत नहीं होती. साथ ही, यह कई बेहतर सुविधाएं उपलब्ध कराता है. जैसे, टास्क को एक साथ जोड़ना या किसी टास्क की स्थिति की जांच करना. ज़्यादा जानने के लिए, WorkManager लेख पढ़ें.
ऐप्लिकेशन के चलने के दौरान, नेटवर्क कनेक्टिविटी की निगरानी करना
चल रहे ऐप्लिकेशन, रजिस्टर किए गए BroadcastReceiver की मदद से, अब भी CONNECTIVITY_CHANGE को सुन सकते हैं. हालांकि, ConnectivityManager API, कॉलबैक का अनुरोध करने के लिए ज़्यादा मज़बूत तरीका उपलब्ध कराता है. ऐसा सिर्फ़ तब होता है, जब तय की गई नेटवर्क की शर्तें पूरी होती हैं.
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() -
TriggerContentUriऑब्जेक्ट कोJobInfoमें पास करता है. AContentObserverशामिल किए गए कॉन्टेंट यूआरआई की निगरानी करता है. अगर किसी जॉब से कई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()); }
जब सिस्टम, तय किए गए कॉन्टेंट यूआरआई में बदलाव की रिपोर्ट करता है, तो आपके ऐप्लिकेशन को कॉलबैक मिलता है. साथ ही, MediaContentJob.class में onStartJob() तरीके में JobParameters ऑब्जेक्ट पास किया जाता है.
यह तय करना कि किन कॉन्टेंट अथॉरिटी ने जॉब ट्रिगर की
Android 7.0 (एपीआई लेवल 24), JobParameters को
भी बढ़ाता है, ताकि आपका ऐप्लिकेशन, उन कॉन्टेंट अथॉरिटी
और यूआरआई के बारे में काम की जानकारी पा सके जिन्होंने जॉब ट्रिगर की:
-
Uri[] getTriggeredContentUris() -
यूआरआई का एक ऐसा कलेक्शन दिखाता है जिन्होंने जॉब ट्रिगर की है. अगर किसी भी यूआरआई ने जॉब ट्रिगर नहीं की है (उदाहरण के लिए, जॉब को समयसीमा या किसी अन्य वजह से ट्रिगर किया गया था) या बदले गए यूआरआई की संख्या 50 से ज़्यादा है, तो यह
null`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) इन समस्याओं को कम करने के लिए कदम उठाता है. फिर भी, हमारा सुझाव है कि आप अपने ऐप्लिकेशन को पूरी तरह से इन बैकग्राउंड प्रोसेस के इस्तेमाल के बिना चलाने के लिए ऑप्टिमाइज़ करें.
- ऐसी स्थितियों को सिम्युलेट करने के लिए जहां इंप्लिसिट ब्रॉडकास्ट और बैकग्राउंड में चलने वाली सेवाएं उपलब्ध नहीं हैं, यह कमांड डालें:
-
$ 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