बैकग्राउंड ऑप्टिमाइज़ेशन

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

इस समस्या को कम करने के लिए, Android 7.0 (एपीआई लेवल 24) पर ये पाबंदियां लागू होती हैं:

  • Android 7.0 (एपीआई लेवल 24) और उसके बाद के वर्शन को टारगेट करने वाले ऐप्लिकेशन को CONNECTIVITY_ACTION का ब्रॉडकास्ट नहीं मिलेगा. ऐसा तब होगा, जब वे मेनिफ़ेस्ट में अपने ब्रॉडकास्ट रिसीवर की जानकारी दें. अगर ऐप्लिकेशन ने अपने BroadcastReceiver को Context.registerReceiver() में रजिस्टर किया है और वह कॉन्टेक्स्ट अब भी मान्य है, तो उन्हें CONNECTIVITY_ACTION ब्रॉडकास्ट मिलेंगे.
  • ऐप्लिकेशन, 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 फ़्रेमवर्क में पहले से मौजूद हैं. हालांकि, उनमें से कौनसा तरीका चुनना है, यह इस बात पर निर्भर करता है कि आपको अपने ऐप्लिकेशन से क्या हासिल करना है.

ध्यान दें: Context.registerReceiver() के साथ रजिस्टर किए गए BroadcastReceiver को, ऐप्लिकेशन के चलने के दौरान ये ब्रॉडकास्ट मिलते रहेंगे.

बिना मेज़र किए जाने वाले कनेक्शन पर नेटवर्क जॉब शेड्यूल करना

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 services की ज़रूरत नहीं होती. साथ ही, यह कई ऐडवांस सुविधाएं भी देता है. जैसे, टास्क को एक साथ जोड़ना या किसी टास्क का स्टेटस देखना. ज़्यादा जानने के लिए, 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()
TriggerContentUri ऑब्जेक्ट को JobInfo में पास करता है. 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());
}

जब सिस्टम इस कॉन्टेंट यूआरआई में बदलाव की रिपोर्ट करता है, तो आपके ऐप्लिकेशन को कॉलबैक मिलता है और MediaContentJob.class में onStartJob() वाले तरीके को JobParameters ऑब्जेक्ट भेजा जाता है.

यह पता लगाना कि कॉन्टेंट की किन संस्थाओं ने कोई जॉब ट्रिगर किया

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) के इन कमांड की मदद से, बैकग्राउंड प्रोसेस बंद होने पर ऐप्लिकेशन के व्यवहार की जांच की जा सकती है:

  • ऐसी स्थितियों को सिम्युलेट करने के लिए जहां डिफ़ॉल्ट ब्रॉडकास्ट और बैकग्राउंड सेवाएं उपलब्ध नहीं हैं, यह कमांड डालें:
  • $ 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