পটভূমি অপ্টিমাইজেশান

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

এই সমস্যাটি দূর করতে, Android 7.0 (API স্তর 24) নিম্নলিখিত বিধিনিষেধগুলি প্রয়োগ করে:

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

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

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

ব্যবহারকারী-সূচিত বিধিনিষেধ

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

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

যদি কোনো অ্যাপ অ্যান্ড্রয়েড ভাইটাল- এ বর্ণিত কিছু খারাপ আচরণ প্রদর্শন করে, তাহলে সিস্টেম ব্যবহারকারীকে সেই অ্যাপের সিস্টেম রিসোর্সে অ্যাক্সেস সীমিত করার অনুরোধ জানাতে পারে।

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

  • অত্যধিক ওয়েক লক: স্ক্রিন বন্ধ থাকলে 1টি আংশিক ওয়েক লক এক ঘন্টা ধরে রাখা হয়
  • অত্যধিক ব্যাকগ্রাউন্ড পরিষেবা: অ্যাপ যদি 26-এর কম এপিআই স্তরকে লক্ষ্য করে এবং অত্যধিক ব্যাকগ্রাউন্ড পরিষেবা থাকে

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

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

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

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

নেটওয়ার্ক কার্যকলাপ সম্প্রচার গ্রহণের উপর নিষেধাজ্ঞা

Android 7.0 (API স্তর 24) টার্গেট করা অ্যাপগুলি CONNECTIVITY_ACTION সম্প্রচার গ্রহণ করে না যদি তারা তাদের ম্যানিফেস্টে সেগুলি পাওয়ার জন্য নিবন্ধন করে এবং এই সম্প্রচারের উপর নির্ভর করে এমন প্রক্রিয়াগুলি শুরু হবে না৷ এটি এমন অ্যাপগুলির জন্য একটি সমস্যা তৈরি করতে পারে যেগুলি নেটওয়ার্ক পরিবর্তনের জন্য শুনতে চায় বা যখন ডিভাইসটি একটি মিটারবিহীন নেটওয়ার্কের সাথে সংযোগ করে তখন বাল্ক নেটওয়ার্ক ক্রিয়াকলাপ সম্পাদন করতে চায়৷ এই বিধিনিষেধটি পেতে বেশ কয়েকটি সমাধান ইতিমধ্যেই অ্যান্ড্রয়েড ফ্রেমওয়ার্কে বিদ্যমান, তবে সঠিকটি বেছে নেওয়া নির্ভর করে আপনি আপনার অ্যাপটি কী করতে চান তার উপর।

দ্রষ্টব্য: অ্যাপটি চলাকালীন Context.registerReceiver() এর সাথে নিবন্ধিত একটি BroadcastReceiver এই সম্প্রচারগুলি গ্রহণ করতে থাকে।

মিটারবিহীন সংযোগে নেটওয়ার্ক কাজের সময়সূচী করুন

আপনার JobInfo অবজেক্ট তৈরি করতে JobInfo.Builder ক্লাস ব্যবহার করার সময়, setRequiredNetworkType() পদ্ধতি প্রয়োগ করুন এবং JobInfo.NETWORK_TYPE_UNMETERED একটি কাজের প্যারামিটার হিসাবে পাস করুন। নিম্নলিখিত কোড নমুনা একটি পরিষেবা চালানোর জন্য নির্ধারিত করে যখন ডিভাইসটি একটি মিটারবিহীন নেটওয়ার্কের সাথে সংযোগ করে এবং চার্জ করা হয়:

কোটলিন

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.classonStartJob() পদ্ধতি চালানোর জন্য একটি কলব্যাক পায়। JobScheduler বাস্তবায়নের আরও উদাহরণ দেখতে, JobScheduler নমুনা অ্যাপটি দেখুন।

JobScheduler-এর একটি নতুন বিকল্প হল WorkManager, একটি API যা আপনাকে ব্যাকগ্রাউন্ডের কাজগুলিকে সময়সূচী করতে দেয় যার জন্য অ্যাপের প্রক্রিয়াটি আশেপাশে থাকুক বা না থাকুক। WorkManager কাজ চালানোর জন্য উপযুক্ত উপায় বেছে নেয় (হয় সরাসরি আপনার অ্যাপ প্রক্রিয়ার একটি থ্রেডে সেইসাথে JobScheduler, FirebaseJobDispatcher, বা AlarmManager ব্যবহার করে) ডিভাইস API স্তরের মতো বিষয়গুলির উপর ভিত্তি করে। অতিরিক্তভাবে, WorkManager-এর প্লে পরিষেবার প্রয়োজন হয় না এবং বেশ কিছু উন্নত বৈশিষ্ট্য প্রদান করে, যেমন কাজগুলিকে একসাথে চেইন করা বা একটি টাস্কের স্থিতি পরীক্ষা করা। আরও জানতে, WorkManager দেখুন।

অ্যাপটি চলাকালীন নেটওয়ার্ক সংযোগ নিরীক্ষণ করুন

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

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

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

ছবি এবং ভিডিও সম্প্রচার প্রাপ্তির উপর নিষেধাজ্ঞা

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

বিষয়বস্তু URI পরিবর্তনের উপর কাজ ট্রিগার করুন

কন্টেন্ট ইউআরআই পরিবর্তনে কাজ ট্রিগার করতে, Android 7.0 (API লেভেল 24) নিম্নলিখিত পদ্ধতিগুলির সাথে JobInfo API প্রসারিত করে:

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

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

যখন সিস্টেম URI, MEDIA_URI বিষয়বস্তুতে একটি পরিবর্তনের রিপোর্ট করে তখন নিম্নলিখিত নমুনা কোডটি ট্রিগার করার জন্য একটি কাজ নির্ধারণ করে:

কোটলিন

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() পদ্ধতিতে পাস করা হয়।

কোন বিষয়বস্তু কর্তৃপক্ষ একটি কাজ ট্রিগার করেছে তা নির্ধারণ করুন

অ্যান্ড্রয়েড 7.0 (এপিআই লেভেল 24) আপনার অ্যাপকে কোন বিষয়বস্তু কর্তৃপক্ষ এবং ইউআরআই কাজটি ট্রিগার করেছে সে সম্পর্কে দরকারী তথ্য পেতে JobParameters প্রসারিত করে:

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

নিম্নলিখিত নমুনা কোড JobService.onStartJob() পদ্ধতিকে ওভাররাইড করে এবং বিষয়বস্তু কর্তৃপক্ষ এবং ইউআরআইগুলি রেকর্ড করে যা কাজটি ট্রিগার করেছে:

কোটলিন

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

আপনার অ্যাপটিকে আরও অপ্টিমাইজ করুন

কম মেমরির ডিভাইসে বা কম মেমরির অবস্থায় চালানোর জন্য আপনার অ্যাপগুলিকে অপ্টিমাইজ করা কর্মক্ষমতা এবং ব্যবহারকারীর অভিজ্ঞতা উন্নত করতে পারে। ব্যাকগ্রাউন্ড পরিষেবা এবং ম্যানিফেস্ট-নিবন্ধিত অন্তর্নিহিত সম্প্রচার রিসিভারগুলির উপর নির্ভরতা অপসারণ করা আপনার অ্যাপকে এই ধরনের ডিভাইসগুলিতে আরও ভালভাবে চলতে সাহায্য করতে পারে। যদিও অ্যান্ড্রয়েড 7.0 (এপিআই স্তর 24) এই সমস্যাগুলির কিছু কমাতে পদক্ষেপ নেয়, তবে এটি সুপারিশ করা হয় যে আপনি এই ব্যাকগ্রাউন্ড প্রক্রিয়াগুলি সম্পূর্ণরূপে ব্যবহার না করেই আপনার অ্যাপটি চালানোর জন্য অপ্টিমাইজ করুন৷

নিম্নলিখিত অ্যান্ড্রয়েড ডিবাগ ব্রিজ (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