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

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

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

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

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

खास पाबंदियों की जानकारी यहां दी गई है पावर मैनेजमेंट से जुड़ी पाबंदियां.

नेटवर्क गतिविधि के ब्रॉडकास्ट पाने से जुड़ी पाबंदियां

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

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

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

JobInfo.Builder क्लास का इस्तेमाल करते समय अपना JobInfo ऑब्जेक्ट बनाने के लिए, setRequiredNetworkType() तरीका लागू करें और JobInfo.NETWORK_TYPE_UNMETERED को जॉब पैरामीटर के तौर पर पास करें. यहां दिया गया कोड सैंपल जब डिवाइस किसी ऐसे डिवाइस से कनेक्ट होता है जिस पर डेटा इस्तेमाल की कोई सीमा नहीं है, तो सेवा को चलाने के लिए शेड्यूल करता है नेटवर्क और चार्ज हो रहा है:

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

JobInfo.TriggerContentUri()
कॉन्टेंट यूआरआई में बदलाव होने पर, जॉब को ट्रिगर करने के लिए ज़रूरी पैरामीटर को एन्कैप्सुलेट करता है.
JobInfo.Builder.addTriggerContentUri()
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है यह TriggerContentUri ऑब्जेक्ट को JobInfo को पास करता है. ContentObserver एनकैप्सुलेट किए गए कॉन्टेंट यूआरआई पर नज़र रखता है. अगर किसी नौकरी से जुड़े एक से ज़्यादा TriggerContentUri ऑब्जेक्ट हैं, तो सिस्टम एक कॉलबैक देता है. भले ही, वह कॉन्टेंट के सिर्फ़ एक यूआरआई में हुए बदलाव की रिपोर्ट करता हो.
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS फ़्लैग को इसमें जोड़ें दिए गए यूआरआई के किसी भी डिसेंडेंट में बदलाव होने पर, जॉब ट्रिगर किया जा सकता है. यह फ़्लैग यह registerContentObserver() को पास किए गए notifyForDescendants पैरामीटर से मेल खाता है.

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

यहां दिया गया सैंपल कोड, एक जॉब को शेड्यूल करता है, ताकि जब सिस्टम, कॉन्टेंट के यूआरआई MEDIA_URI में बदलाव की सूचना दे, तो वह जॉब ट्रिगर हो जाए:

KotlinJava
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)
}
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 ऑब्जेक्ट होता है onStartJob() को भेजा गया MediaContentJob.class में तरीका.

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

Android 7.0 (एपीआई लेवल 24) JobParameters को इससे आपके ऐप्लिकेशन को, उस कॉन्टेंट के बारे में काम की जानकारी मिल सकेगी जिसके लिए कॉन्टेंट की अनुमति मिली है और यूआरआई ने जॉब को ट्रिगर किया:

Uri[] getTriggeredContentUris()
उन यूआरआई की सूची दिखाता है जिन्होंने जॉब को ट्रिगर किया है. अगर किसी यूआरआई ने जॉब को ट्रिगर नहीं किया है (उदाहरण के लिए, जॉब को समयसीमा या किसी और वजह से ट्रिगर किया गया था) या बदले गए यूआरआई की संख्या 50 से ज़्यादा है, तो यह null होगा.
String[] getTriggeredContentAuthorities()
अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है उन कॉन्टेंट अथॉरिटी की स्ट्रिंग अरे दिखाता है जिन्होंने जॉब को ट्रिगर किया है. अगर लौटाया गया अरे null नहीं है, तो getTriggeredContentUris() का इस्तेमाल करें का इस्तेमाल करें.

यहां दिया गया सैंपल कोड, JobService.onStartJob() तरीके को बदल देता है और उन कॉन्टेंट अथॉरिटी और यूआरआई को रिकॉर्ड करता है जिन्होंने जॉब को ट्रिगर किया है:

KotlinJava
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
}
@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