ব্যাকগ্রাউন্ড অপ্টিমাইজেশন

ব্যাকগ্রাউন্ড প্রসেস মেমরি ও ব্যাটারি বেশি খরচ করতে পারে। যেমন, একটি ইমপ্লিসিট ব্রডকাস্ট অনেক ব্যাকগ্রাউন্ড প্রসেস শুরু করতে পারে যা এটি শোনার জন্য রেজিস্টার করা হয়েছে, এমনকি সেই প্রসেসগুলি বেশি কাজ নাও করতে পারে। এটি ডিভাইসের পারফর্ম্যান্স ও ব্যবহারকারীর অভিজ্ঞতা, উভয়ের উপরেই যথেষ্ট প্রভাব ফেলতে পারে।

এই সমস্যা কমাতে, Android 7.0 (API লেভেল ২৪) নিম্নলিখিত বিধিনিষেধ প্রয়োগ করে:

  • Android 7.0 (API লেভেল ২৪) এবং তার পরবর্তী ভার্সনকে টার্গেট করা অ্যাপ CONNECTIVITY_ACTION ব্রডকাস্ট পায় না, যদি তারা ম্যানিফেস্টে তাদের ব্রডকাস্ট রিসিভার ঘোষণা করে। অ্যাপগুলি এখনও CONNECTIVITY_ACTION ব্রডকাস্ট পাবে যদি তারা Context.registerReceiver()-এর সাথে তাদের BroadcastReceiver রেজিস্টার করে এবং সেই প্রসঙ্গ এখনও বৈধ থাকে।
  • অ্যাপ ACTION_NEW_PICTURE বা ACTION_NEW_VIDEO ব্রডকাস্ট পাঠাতে বা গ্রহণ করতে পারবে না। এই অপ্টিমাইজেশন সব অ্যাপকে প্রভাবিত করে, শুধু Android 7.0 (API লেভেল ২৪) টার্গেট করা অ্যাপকে নয়।

আপনার অ্যাপ যদি এইসব ইনটেন্টের কোনও একটি ব্যবহার করে, তাহলে যত তাড়াতাড়ি সম্ভব সেগুলির উপর থেকে নির্ভরতা সরিয়ে নিন যাতে Android 7.0 বা তার পরবর্তী যেকোনও ভার্সনে চলা ডিভাইসকে আপনি সঠিকভাবে টার্গেট করতে পারেন। এইসব ইমপ্লিসিট ব্রডকাস্টের প্রয়োজনীয়তা কমানোর জন্য Android ফ্রেমওয়ার্ক একাধিক সমাধান প্রদান করে। যেমন, JobScheduler এবং নতুন WorkManager নেটওয়ার্ক অপারেশন শিডিউল করার জন্য শক্তিশালী মেকানিজম প্রদান করে, যখন নির্দিষ্ট শর্ত, যেমন আনমিটার্ড নেটওয়ার্কের সাথে কানেকশন, পূরণ হয়। কন্টেন্ট প্রোভাইডারে হওয়া পরিবর্তনের প্রতিক্রিয়া জানাতে আপনি এখন JobScheduler-ও ব্যবহার করতে পারবেন। JobInfo অবজেক্ট সেইসব প্যারামিটার এনক্যাপসুলেট করে যা JobScheduler আপনার জব শিডিউল করার জন্য ব্যবহার করে। জবের শর্ত পূরণ হলে, সিস্টেম আপনার অ্যাপের JobService-এ এই জব এক্সিকিউট করে।

এই পৃষ্ঠায় আমরা শিখব কীভাবে বিকল্প পদ্ধতি ব্যবহার করতে হয়, যেমন JobScheduler, যাতে আপনার অ্যাপকে এইসব নতুন বিধিনিষেধের সাথে মানানসই করে তোলা যায়।

ব্যবহারকারীর শুরু করা বিধিনিষেধ

সিস্টেম সেটিংসের মধ্যে ব্যাটারির ব্যবহার পৃষ্ঠায়, ব্যবহারকারী নিম্নলিখিত বিকল্পগুলির মধ্যে থেকে বেছে নিতে পারবেন:

  • কোনও বাধা নেই: ব্যাকগ্রাউন্ডে সব কাজ করার অনুমতি দেয়, যার ফলে ব্যাটারি বেশি খরচ হতে পারে।
  • অপ্টিমাইজ করা (ডিফল্ট): ব্যবহারকারী কীভাবে অ্যাপের সাথে ইন্টার‍্যাক্ট করেন তার উপর ভিত্তি করে, ব্যাকগ্রাউন্ডে কাজ করার জন্য অ্যাপের ক্ষমতা অপ্টিমাইজ করুন।
  • সীমাবদ্ধ: ব্যাকগ্রাউন্ডে কোনও অ্যাপ চলা সম্পূর্ণভাবে বন্ধ করে দেয়। অ্যাপ প্রত্যাশা অনুযায়ী কাজ নাও করতে পারে।

কোনও অ্যাপ যদি Android vitals-এ বর্ণিত কিছু খারাপ পারফর্ম্যান্স দেখায়, তাহলে সিস্টেম ব্যবহারকারীকে সেই অ্যাপের সিস্টেম রিসোর্সে অ্যাক্সেস সীমিত করার জন্য প্রম্পট করতে পারে।

সিস্টেম যদি লক্ষ্য করে যে কোনও অ্যাপ অতিরিক্ত রিসোর্স ব্যবহার করছে, তাহলে এটি ব্যবহারকারীকে বিজ্ঞপ্তি দেয় এবং অ্যাপের অ্যাকশন সীমিত করার বিকল্প দেয়। যেসব আচরণের জন্য বিজ্ঞপ্তি পাঠানো হতে পারে তার মধ্যে এগুলি অন্তর্ভুক্ত:

  • অতিরিক্ত ওয়েক লক: স্ক্রিন বন্ধ থাকার সময় এক ঘণ্টার জন্য ১টি আংশিক ওয়েক লক চালু আছে
  • অতিরিক্ত ব্যাকগ্রাউন্ড পরিষেবা: অ্যাপ যদি ২৬-এর কম API লেভেল টার্গেট করে এবং এতে অতিরিক্ত ব্যাকগ্রাউন্ড পরিষেবা থাকে

ডিভাইস প্রস্তুতকারক সুনির্দিষ্ট বিধিনিষেধ নির্ধারণ করেন। যেমন, AOSP বিল্ডে Android 9 (API লেভেল ২৮) বা তার পরবর্তী যেকোনও ভার্সন থাকলে, ব্যাকগ্রাউন্ডে "সীমাবদ্ধ" অবস্থায় চলা অ্যাপের ক্ষেত্রে নিম্নলিখিত সীমাবদ্ধতা প্রযোজ্য:

  • ফোরগ্রাউন্ড পরিষেবা চালু করা যাচ্ছে না
  • আগে থেকে থাকা ফোরগ্রাউন্ড পরিষেবাগুলি ফোরগ্রাউন্ড থেকে সরানো হয়েছে
  • অ্যালার্ম ট্রিগার করা হয়নি
  • জব এক্সিকিউট করা হয়নি

এছাড়াও, কোনও অ্যাপ Android 13 (API লেভেল ৩৩) বা তার পরবর্তী কোনও ভার্সনকে টার্গেট করলে এবং "সীমাবদ্ধ" অবস্থায় থাকলে, অন্য কোনও কারণে অ্যাপটি চালু না হওয়া পর্যন্ত সিস্টেম BOOT_COMPLETED ব্রডকাস্ট বা LOCKED_BOOT_COMPLETED ব্রডকাস্ট ডেলিভার করে না।

নির্দিষ্ট বিধিনিষেধগুলি পাওয়ার ম্যানেজমেন্ট সংক্রান্ত বিধিনিষেধ-এ তালিকাভুক্ত করা আছে।

নেটওয়ার্ক অ্যাক্টিভিটি ব্রডকাস্ট পাওয়ার উপর বিধিনিষেধ

Android 7.0 (API লেভেল ২৪) টার্গেট করা অ্যাপ 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)
}

জাভা

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, এটি এমন একটি API যা আপনাকে ব্যাকগ্রাউন্ড টাস্ক শিডিউল করার অনুমতি দেয়, যেগুলি সম্পূর্ণ করার গ্যারান্টি প্রয়োজন, অ্যাপ প্রসেস চালু আছে কিনা তা নির্বিশেষে। WorkManager কাজটি চালানোর জন্য উপযুক্ত উপায় বেছে নেয় (সরাসরি আপনার অ্যাপ প্রসেসের একটি থ্রেডে পাশাপাশি JobScheduler, FirebaseJobDispatcher, বা AlarmManager ব্যবহার করে) ডিভাইসের API লেভেলের মতো ফ্যাক্টরের উপর ভিত্তি করে। এছাড়াও, WorkManager-এর জন্য Play পরিষেবার প্রয়োজন হয় না এবং এটি একাধিক উন্নত ফিচার প্রদান করে, যেমন একসাথে টাস্ক চেইন করা বা কোনও টাস্কের স্ট্যাটাস চেক করা। আরও জানতে, WorkManager দেখুন।

অ্যাপ চলাকালীন নেটওয়ার্ক কানেক্টিভিটি মনিটর করা

যেসব অ্যাপ চলছে সেগুলি এখনও রেজিস্টার করা BroadcastReceiver-এর মাধ্যমে CONNECTIVITY_CHANGE-এর জন্য শুনতে পারে। তবে, ConnectivityManager API আরও শক্তিশালী পদ্ধতি প্রদান করে যার মাধ্যমে শুধুমাত্র নির্দিষ্ট নেটওয়ার্ক সংক্রান্ত শর্ত পূরণ হলে কলব্যাকের অনুরোধ করা যায়।

NetworkRequest অবজেক্ট NetworkCapabilities-এর পরিপ্রেক্ষিতে নেটওয়ার্ক কলব্যাকের প্যারামিটার নির্ধারণ করে। আপনি NetworkRequest.Builder ক্লাস ব্যবহার করে NetworkRequest অবজেক্ট তৈরি করেন। registerNetworkCallback() তারপর NetworkRequest অবজেক্টটি সিস্টেমে পাস করে। নেটওয়ার্কের শর্ত পূরণ হলে, অ্যাপটি ConnectivityManager.NetworkCallback ক্লাসে সংজ্ঞায়িত onAvailable() পদ্ধতি কার্যকর করার জন্য একটি কলব্যাক পায়।

অ্যাপটি বন্ধ না হওয়া পর্যন্ত বা এটি unregisterNetworkCallback()-এ কল না করা পর্যন্ত অ্যাপটি কলব্যাক পেতে থাকে।

ছবি ও ভিডিও ব্রডকাস্ট পাওয়ার ক্ষেত্রে বিধিনিষেধ

Android 7.0 (API লেভেল ২৪)-এ, অ্যাপগুলি ACTION_NEW_PICTURE বা ACTION_NEW_VIDEO ব্রডকাস্ট পাঠাতে বা গ্রহণ করতে পারে না। এই বিধিনিষেধ পারফর্ম্যান্স ও ব্যবহারকারীর অভিজ্ঞতার উপর প্রভাব কম করতে সাহায্য করে, যখন নতুন ছবি বা ভিডিও প্রসেস করার জন্য একাধিক অ্যাপকে চালু করতে হয়। Android 7.0 (API লেভেল ২৪) বিকল্প সমাধান প্রদান করতে JobInfo এবং JobParameters-এর এক্সটেনশন করে।

কন্টেন্ট URI পরিবর্তন হলে জব ট্রিগার করুন

কন্টেন্ট URI পরিবর্তনের উপর ভিত্তি করে কাজ ট্রিগার করতে, Android 7.0 (API লেভেল ২৪) JobInfo API-কে নিম্নলিখিত পদ্ধতিতে এক্সটেন্ড করে:

JobInfo.TriggerContentUri()
কন্টেন্ট URI পরিবর্তনের ক্ষেত্রে কোনও কাজ ট্রিগার করার জন্য প্রয়োজনীয় প্যারামিটার এনক্যাপসুলেট করে।
JobInfo.Builder.addTriggerContentUri()
TriggerContentUri অবজেক্টকে JobInfo-এ পাস করে। ContentObserver এনক্যাপসুলেট করা কন্টেন্ট URI মনিটর করে। কোনও কাজের সাথে একাধিক TriggerContentUri অবজেক্ট যুক্ত থাকলে, সিস্টেম একটি কলব্যাক প্রদান করে, এমনকি এটি শুধুমাত্র একটি কন্টেন্ট URI-তে পরিবর্তন রিপোর্ট করলেও।
প্রদত্ত URI-এর কোনও ডিসেন্ডেন্ট পরিবর্তিত হলে জব ট্রিগার করতে TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS ফ্ল্যাগ যোগ করুন। এই ফ্ল্যাগ registerContentObserver()-এ পাস করা notifyForDescendants প্যারামিটারের সাথে সম্পর্কিত।

মনে রাখবেন: TriggerContentUri()-এর সাথে setPeriodic() বা setPersisted() একসাথে ব্যবহার করা যাবে না। কন্টেন্টে হওয়া পরিবর্তন ক্রমাগত মনিটর করতে, অ্যাপের JobService সবচেয়ে সাম্প্রতিক কলব্যাক ম্যানেজ করা শেষ করার আগে নতুন JobInfo শিডিউল করুন।

নিম্নলিখিত স্যাম্পেল কোডটি সিস্টেম যখন কন্টেন্ট URI, 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)
}

জাভা

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());
}

সিস্টেম নির্দিষ্ট কন্টেন্ট URI(গুলি)-তে কোনও পরিবর্তন রিপোর্ট করলে, আপনার অ্যাপ একটি কলব্যাক পায় এবং একটি JobParameters অবজেক্ট MediaContentJob.class-এর onStartJob() মেথডে পাস করা হয়।

কোন কন্টেন্ট অথরিটি কোনও কাজ ট্রিগার করেছে তা নির্ধারণ করুন

Android 7.0 (API লেভেল 24) JobParameters-কে আরও প্রসারিত করে যাতে আপনার অ্যাপ কোন কন্টেন্ট অথরিটি এবং URI-এর কারণে জব ট্রিগার হয়েছে সেই সম্পর্কে প্রয়োজনীয় তথ্য পেতে পারে:

Uri[] getTriggeredContentUris()
URI-এর একটি অ্যারে রিটার্ন করে যা জব ট্রিগার করেছে। কোনও URI জব ট্রিগার না করলে (যেমন, সময়সীমা বা অন্য কোনও কারণে জব ট্রিগার করা হলে) অথবা পরিবর্তিত URI-এর সংখ্যা ৫০-এর বেশি হলে, এটি null হবে।
String[] getTriggeredContentAuthorities()
কন্টেন্ট অথরিটির স্ট্রিং অ্যারে দেখায় যা জব ট্রিগার করেছে। ফেরত আসা অ্যারে null না হলে, কোন URI পরিবর্তিত হয়েছে তার বিবরণ পেতে getTriggeredContentUris() ব্যবহার করুন।

নিম্নলিখিত স্যাম্পেল কোড JobService.onStartJob() পদ্ধতি ওভাররাইড করে এবং কন্টেন্ট অথরিটি ও URI রেকর্ড করে যা জব ট্রিগার করেছে:

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
}

জাভা

@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 (API লেভেল 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