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

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

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

डिवाइस बनाने वाली कंपनी, यह तय करती है कि कौनसी पाबंदियां लगाई जाएंगी. उदाहरण के लिए, Android 9 (एपीआई लेवल 28) या उसके बाद के वर्शन पर काम करने वाले AOSP बिल्ड पर, बैकग्राउंड में चल रहे "प्रतिबंधित" स्थिति वाले ऐप्लिकेशन पर ये पाबंदियां लागू होती हैं:

  • फ़ोरग्राउंड सेवाएं लॉन्च नहीं की जा सकतीं
  • मौजूदा फ़ोरग्राउंड सेवाओं को फ़ोरग्राउंड से हटा दिया जाता है
  • अलार्म ट्रिगर नहीं होते
  • जॉब पूरे नहीं होते

इसके अलावा, अगर कोई ऐप्लिकेशन 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 फ़्लैग जोड़ें, ताकि दिए गए यूआरआई के किसी भी डिसेंडेंट में बदलाव होने पर नौकरी ट्रिगर हो जाए. यह फ़्लैग, notifyForDescendants पैरामीटर से मेल खाता है. इसे registerContentObserver() में पास किया जाता है.

ध्यान दें: TriggerContentUri() का इस्तेमाल, setPeriodic() या setPersisted() के साथ नहीं किया जा सकता. कॉन्टेंट में होने वाले बदलावों को लगातार मॉनिटर करने के लिए, JobInfo को शेड्यूल करें. ऐसा तब करें, जब ऐप्लिकेशन JobService सबसे हालिया कॉलबैक को प्रोसेस कर रहा हो.

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

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