ব্যাকগ্রাউন্ড প্রসেসগুলো মেমোরি এবং ব্যাটারির ওপর ব্যাপক চাপ সৃষ্টি করতে পারে। উদাহরণস্বরূপ, একটি ইমপ্লিসিট ব্রডকাস্ট এমন অনেক ব্যাকগ্রাউন্ড প্রসেস চালু করে দিতে পারে যেগুলো এটি শোনার জন্য রেজিস্টার করেছে, যদিও সেই প্রসেসগুলো খুব বেশি কাজ নাও করতে পারে। এটি ডিভাইসের পারফরম্যান্স এবং ব্যবহারকারীর অভিজ্ঞতা উভয়ের ওপরই একটি উল্লেখযোগ্য প্রভাব ফেলতে পারে।
এই সমস্যাটি নিরসনের জন্য, অ্যান্ড্রয়েড ৭.০ (এপিআই লেভেল ২৪) নিম্নলিখিত সীমাবদ্ধতাগুলো প্রয়োগ করে:
- অ্যান্ড্রয়েড ৭.০ (এপিআই লেভেল ২৪) এবং তার উচ্চতর সংস্করণকে লক্ষ্য করে তৈরি অ্যাপগুলো, যদি তাদের ব্রডকাস্ট রিসিভার ম্যানিফেস্টে ঘোষণা করা থাকে, তাহলে
CONNECTIVITY_ACTIONব্রডকাস্ট গ্রহণ করে না। তবে, অ্যাপগুলোCONNECTIVITY_ACTIONব্রডকাস্ট গ্রহণ করবে যদি তারাContext.registerReceiver()ব্যবহার করে তাদেরBroadcastReceiverরেজিস্টার করে এবং সেই কনটেক্সটটি বৈধ থাকে। - অ্যাপগুলো
ACTION_NEW_PICTUREবাACTION_NEW_VIDEOব্রডকাস্ট পাঠাতে বা গ্রহণ করতে পারবে না। এই অপটিমাইজেশনটি শুধুমাত্র Android 7.0 (API লেভেল 24) টার্গেট করা অ্যাপগুলোকেই নয়, বরং সমস্ত অ্যাপকেই প্রভাবিত করে।
আপনার অ্যাপ যদি এই ইন্টেন্টগুলোর কোনোটি ব্যবহার করে, তবে যত তাড়াতাড়ি সম্ভব সেগুলোর উপর থেকে নির্ভরতা দূর করা উচিত, যাতে আপনি অ্যান্ড্রয়েড ৭.০ বা তার উচ্চতর সংস্করণে চালিত ডিভাইসগুলোকে সঠিকভাবে টার্গেট করতে পারেন। অ্যান্ড্রয়েড ফ্রেমওয়ার্ক এই অন্তর্নিহিত ব্রডকাস্টগুলোর প্রয়োজনীয়তা কমানোর জন্য বেশ কিছু সমাধান প্রদান করে। উদাহরণস্বরূপ, JobScheduler এবং নতুন WorkManager নির্দিষ্ট শর্ত পূরণ হলে, যেমন একটি আনমিটারড নেটওয়ার্কের সাথে সংযোগ স্থাপন হলে, নেটওয়ার্ক অপারেশন শিডিউল করার জন্য শক্তিশালী ব্যবস্থা প্রদান করে। আপনি এখন কন্টেন্ট প্রোভাইডারের পরিবর্তনে সাড়া দেওয়ার জন্যও JobScheduler ব্যবহার করতে পারেন। JobInfo অবজেক্টগুলো সেই প্যারামিটারগুলোকে এনক্যাপসুলেট করে যা JobScheduler আপনার জব শিডিউল করার জন্য ব্যবহার করে। যখন জবের শর্তগুলো পূরণ হয়, তখন সিস্টেম আপনার অ্যাপের JobService এ এই জবটি সম্পাদন করে।
এই পৃষ্ঠায় আমরা শিখব, কীভাবে JobScheduler মতো বিকল্প পদ্ধতি ব্যবহার করে আপনার অ্যাপকে এই নতুন বিধিনিষেধগুলোর সাথে খাপ খাইয়ে নেওয়া যায়।
ব্যবহারকারী-প্রবর্তিত বিধিনিষেধ
সিস্টেম সেটিংস-এর ব্যাটারি ব্যবহার পেজে , ব্যবহারকারী নিম্নলিখিত বিকল্পগুলো থেকে বেছে নিতে পারেন:
- অবাধ: সমস্ত ব্যাকগ্রাউন্ড কাজের অনুমতি দিন, যা বেশি ব্যাটারি খরচ করতে পারে।
- অপ্টিমাইজড (ডিফল্ট): ব্যবহারকারী অ্যাপটির সাথে কীভাবে ইন্টারঅ্যাক্ট করে, তার উপর ভিত্তি করে অ্যাপটির ব্যাকগ্রাউন্ডে কাজ করার ক্ষমতাকে অপ্টিমাইজ করুন।
- সীমাবদ্ধ: কোনো অ্যাপকে ব্যাকগ্রাউন্ডে চলতে সম্পূর্ণরূপে বাধা দেয়। অ্যাপগুলো প্রত্যাশিতভাবে কাজ নাও করতে পারে।
যদি কোনো অ্যাপ অ্যান্ড্রয়েড ভাইটালস- এ বর্ণিত কিছু খারাপ আচরণ প্রদর্শন করে, তাহলে সিস্টেম ব্যবহারকারীকে সেই অ্যাপটির সিস্টেম রিসোর্স ব্যবহারের সুযোগ সীমিত করার জন্য অনুরোধ করতে পারে।
সিস্টেম যদি লক্ষ্য করে যে কোনো অ্যাপ অতিরিক্ত রিসোর্স ব্যবহার করছে, তবে এটি ব্যবহারকারীকে অবহিত করে এবং অ্যাপটির কার্যকলাপ সীমিত করার সুযোগ দেয়। যেসব আচরণের কারণে এই বিজ্ঞপ্তিটি সক্রিয় হতে পারে, সেগুলো হলো:
- অতিরিক্ত ওয়েক লক: স্ক্রিন বন্ধ থাকা অবস্থায় এক ঘন্টা ধরে একটি আংশিক ওয়েক লক চালু থাকা।
- অতিরিক্ত ব্যাকগ্রাউন্ড সার্ভিস: যদি অ্যাপটি ২৬-এর কম এপিআই লেভেলকে টার্গেট করে এবং এতে অতিরিক্ত ব্যাকগ্রাউন্ড সার্ভিস থাকে।
আরোপিত সুনির্দিষ্ট বিধিনিষেধ ডিভাইস প্রস্তুতকারক দ্বারা নির্ধারিত হয়। উদাহরণস্বরূপ, অ্যান্ড্রয়েড ৯ (এপিআই লেভেল ২৮) বা তার উচ্চতর সংস্করণে চালিত AOSP বিল্ডগুলিতে, ব্যাকগ্রাউন্ডে 'restricted' অবস্থায় থাকা অ্যাপগুলির নিম্নলিখিত সীমাবদ্ধতাগুলি থাকে:
- ফোরগ্রাউন্ড পরিষেবা চালু করা যাচ্ছে না
- বিদ্যমান ফোরগ্রাউন্ড সার্ভিসগুলো ফোরগ্রাউন্ড থেকে সরিয়ে দেওয়া হয়।
- অ্যালার্মগুলো বেজে ওঠে না।
- কাজগুলো সম্পন্ন করা হয় না
এছাড়াও, যদি কোনো অ্যাপ অ্যান্ড্রয়েড ১৩ (এপিআই লেভেল ৩৩) বা তার উচ্চতর সংস্করণকে টার্গেট করে এবং "restricted" অবস্থায় থাকে, তাহলে অ্যাপটি অন্য কোনো কারণে চালু না হওয়া পর্যন্ত সিস্টেম BOOT_COMPLETED বা LOCKED_BOOT_COMPLETED ব্রডকাস্ট পাঠায় না।
নির্দিষ্ট বিধিনিষেধগুলো পাওয়ার ম্যানেজমেন্ট বিধিনিষেধ -এ তালিকাভুক্ত করা হয়েছে।
নেটওয়ার্ক কার্যকলাপ সম্প্রচার গ্রহণের উপর বিধিনিষেধ
অ্যান্ড্রয়েড ৭.০ (এপিআই লেভেল ২৪) টার্গেট করা অ্যাপগুলো তাদের ম্যানিফেস্টে CONNECTIVITY_ACTION ব্রডকাস্ট গ্রহণ করার জন্য রেজিস্টার করলেও তা পায় না, এবং এই ব্রডকাস্টের উপর নির্ভরশীল প্রসেসগুলোও চালু হয় না। যেসব অ্যাপ নেটওয়ার্ক পরিবর্তনের জন্য লিসেন করতে চায় অথবা ডিভাইসটি কোনো আনমিটারড নেটওয়ার্কে সংযুক্ত হলে একসাথে অনেকগুলো নেটওয়ার্ক অ্যাক্টিভিটি সম্পাদন করতে চায়, তাদের জন্য এটি একটি সমস্যা তৈরি করতে পারে। অ্যান্ড্রয়েড ফ্রেমওয়ার্কে এই সীমাবদ্ধতা এড়ানোর জন্য বেশ কিছু সমাধান ইতিমধ্যেই রয়েছে, কিন্তু সঠিকটি বেছে নেওয়া নির্ভর করে আপনার অ্যাপটি কী কাজ সম্পন্ন করতে চায় তার উপর।
দ্রষ্টব্য: Context.registerReceiver() দিয়ে রেজিস্টার করা একটি BroadcastReceiver অ্যাপটি চালু থাকা অবস্থায়ও এই ব্রডকাস্টগুলো গ্রহণ করতে থাকে।
আনমিটারড কানেকশনগুলিতে নেটওয়ার্ক জব শিডিউল করুন
JobInfo.Builder ক্লাস ব্যবহার করে আপনার JobInfo অবজেক্ট তৈরি করার সময়, 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.class এর onStartJob() মেথডটি চালানোর জন্য একটি কলব্যাক পায়। JobScheduler বাস্তবায়নের আরও উদাহরণ দেখতে, JobScheduler স্যাম্পল অ্যাপটি দেখুন।
JobScheduler-এর একটি নতুন বিকল্প হলো WorkManager, একটি API যা আপনাকে এমন ব্যাকগ্রাউন্ড টাস্ক শিডিউল করার সুযোগ দেয়, যেগুলোর সমাপ্তি নিশ্চিত করা প্রয়োজন, অ্যাপ প্রসেসটি চালু থাকুক বা না থাকুক। WorkManager ডিভাইস API লেভেলের মতো বিভিন্ন বিষয়ের উপর ভিত্তি করে কাজটি চালানোর জন্য উপযুক্ত উপায় বেছে নেয় (যেমন, সরাসরি আপনার অ্যাপ প্রসেসের কোনো থ্রেডে অথবা JobScheduler, FirebaseJobDispatcher, বা AlarmManager ব্যবহার করে)। এছাড়াও, WorkManager-এর জন্য Play services-এর প্রয়োজন হয় না এবং এটি বিভিন্ন উন্নত ফিচার প্রদান করে, যেমন টাস্কগুলোকে একসাথে চেইন করা বা কোনো টাস্কের স্ট্যাটাস চেক করা। আরও জানতে, WorkManager দেখুন।
অ্যাপটি চলার সময় নেটওয়ার্ক সংযোগ নিরীক্ষণ করুন।
চলমান অ্যাপগুলো একটি নিবন্ধিত BroadcastReceiver ব্যবহার করে CONNECTIVITY_CHANGE জন্য অপেক্ষা করতে পারে। তবে, ConnectivityManager API শুধুমাত্র নির্দিষ্ট নেটওয়ার্ক শর্ত পূরণ হলেই একটি কলব্যাক অনুরোধ করার জন্য আরও শক্তিশালী একটি পদ্ধতি প্রদান করে।
NetworkRequest অবজেক্টগুলো NetworkCapabilities এর ভিত্তিতে নেটওয়ার্ক কলব্যাকের প্যারামিটারগুলো নির্ধারণ করে। আপনি NetworkRequest.Builder ক্লাস ব্যবহার করে NetworkRequest অবজেক্ট তৈরি করেন। এরপর registerNetworkCallback() ফাংশনটি NetworkRequest অবজেক্টটিকে সিস্টেমে পাঠিয়ে দেয়। যখন নেটওয়ার্কের শর্তগুলো পূরণ হয়, তখন অ্যাপটি তার ConnectivityManager.NetworkCallback ক্লাসে সংজ্ঞায়িত onAvailable() মেথডটি কার্যকর করার জন্য একটি কলব্যাক পায়।
অ্যাপটি বন্ধ না হওয়া পর্যন্ত অথবা unregisterNetworkCallback() কল না করা পর্যন্ত কলব্যাক পেতে থাকে।
ছবি এবং ভিডিও সম্প্রচার গ্রহণের উপর বিধিনিষেধ
অ্যান্ড্রয়েড ৭.০ (এপিআই লেভেল ২৪)-এ, অ্যাপগুলো ACTION_NEW_PICTURE বা ACTION_NEW_VIDEO ব্রডকাস্ট পাঠাতে বা গ্রহণ করতে পারে না। যখন একটি নতুন ছবি বা ভিডিও প্রসেস করার জন্য একাধিক অ্যাপকে জেগে উঠতে হয়, তখন এই সীমাবদ্ধতা পারফরম্যান্স এবং ব্যবহারকারীর অভিজ্ঞতার উপর প্রভাব কমাতে সাহায্য করে। অ্যান্ড্রয়েড ৭.০ (এপিআই লেভেল ২৪) একটি বিকল্প সমাধান প্রদানের জন্য JobInfo এবং JobParameters প্রসারিত করেছে।
কন্টেন্ট ইউআরআই পরিবর্তনের উপর ভিত্তি করে কাজগুলো ট্রিগার করুন
কন্টেন্ট ইউআরআই পরিবর্তনের উপর ভিত্তি করে জব ট্রিগার করার জন্য, অ্যান্ড্রয়েড ৭.০ (এপিআই লেভেল ২৪) নিম্নলিখিত মেথডগুলো দিয়ে JobInfo এপিআই-কে প্রসারিত করেছে:
-
JobInfo.TriggerContentUri() - কন্টেন্ট ইউআরআই পরিবর্তনের ভিত্তিতে কোনো কাজ চালু করার জন্য প্রয়োজনীয় প্যারামিটারগুলো এতে অন্তর্ভুক্ত থাকে।
-
JobInfo.Builder.addTriggerContentUri() -
JobInfoতে একটিTriggerContentUriঅবজেক্ট পাঠানো হয়। একটিContentObserverএনক্যাপসুলেটেড কন্টেন্ট URI-টি পর্যবেক্ষণ করে। যদি একটি জবের সাথে একাধিকTriggerContentUriঅবজেক্ট যুক্ত থাকে, তবে সিস্টেমটি শুধুমাত্র একটি কন্টেন্ট URI-তে পরিবর্তনের রিপোর্ট করলেও একটি কলব্যাক প্রদান করে। - প্রদত্ত URI-এর কোনো ডিসেন্ডেন্ট পরিবর্তিত হলে জবটি ট্রিগার করতে
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTSফ্ল্যাগটি যোগ করুন। এই ফ্ল্যাগটিregisterContentObserver()-এ পাস করাnotifyForDescendantsপ্যারামিটারের অনুরূপ।
দ্রষ্টব্য: TriggerContentUri() একসাথে setPeriodic() বা setPersisted() এর সাথে ব্যবহার করা যাবে না। কন্টেন্টের পরিবর্তন ক্রমাগত পর্যবেক্ষণ করতে, অ্যাপের JobService সর্বশেষ কলব্যাকটি পরিচালনা শেষ করার আগেই একটি নতুন JobInfo শিডিউল করুন।
নিম্নলিখিত নমুনা কোডটি এমন একটি জব শিডিউল করে, যা সিস্টেম কর্তৃক কন্টেন্ট ইউআরআই ( 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-তে কোনো পরিবর্তনের রিপোর্ট করে, তখন আপনার অ্যাপ একটি কলব্যাক পায় এবং MediaContentJob.class এর onStartJob() মেথডে একটি JobParameters অবজেক্ট পাস করা হয়।
কোন বিষয়বস্তু কর্তৃপক্ষ একটি কাজ শুরু করেছে তা নির্ধারণ করুন
অ্যান্ড্রয়েড ৭.০ (এপিআই লেভেল ২৪) JobParameters আরও প্রসারিত করেছে, যার ফলে আপনার অ্যাপ এই বিষয়ে প্রয়োজনীয় তথ্য পেতে পারে যে কোন কন্টেন্ট অথরিটি এবং ইউআরআই দ্বারা জবটি ট্রিগার হয়েছে:
-
Uri[] getTriggeredContentUris() - যেসব URI কাজটি শুরু করেছে, সেগুলোর একটি অ্যারে ফেরত দেয়। যদি কোনো URI কাজটি শুরু না করে (যেমন, কোনো ডেডলাইন বা অন্য কোনো কারণে কাজটি শুরু হয়েছে), অথবা পরিবর্তিত URI-এর সংখ্যা ৫০-এর বেশি হয়, তবে এটি
nullহবে। -
String[] getTriggeredContentAuthorities() - যেসব কন্টেন্ট অথরিটি কাজটি শুরু করেছে, তাদের একটি স্ট্রিং অ্যারে ফেরত দেয়। যদি ফেরত আসা অ্যারেটি
nullনা হয়, তাহলে কোন কোন URI পরিবর্তিত হয়েছে তার বিস্তারিত জানতেgetTriggeredContentUris()ব্যবহার করুন।
নিম্নলিখিত নমুনা কোডটি JobService.onStartJob() মেথডকে ওভাররাইড করে এবং যে কন্টেন্ট অথরিটি ও URI-গুলো জবটি ট্রিগার করেছে, সেগুলোকে রেকর্ড করে:
কোটলিন
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; }
আপনার অ্যাপটিকে আরও অপ্টিমাইজ করুন
কম মেমোরির ডিভাইসে বা কম মেমোরির পরিস্থিতিতে চলার জন্য আপনার অ্যাপগুলোকে অপ্টিমাইজ করলে পারফরম্যান্স এবং ব্যবহারকারীর অভিজ্ঞতা উন্নত হতে পারে। ব্যাকগ্রাউন্ড সার্ভিস এবং ম্যানিফেস্টে নিবন্ধিত ইমপ্লিসিট ব্রডকাস্ট রিসিভারের উপর নির্ভরতা দূর করলে এই ধরনের ডিভাইসে আপনার অ্যাপ আরও ভালোভাবে চলতে পারে। যদিও অ্যান্ড্রয়েড ৭.০ (এপিআই লেভেল ২৪) এই সমস্যাগুলোর কিছু কমানোর জন্য পদক্ষেপ নিয়েছে, তবুও এই ব্যাকগ্রাউন্ড প্রসেসগুলো সম্পূর্ণরূপে ব্যবহার না করে আপনার অ্যাপ চালানোর জন্য অপ্টিমাইজ করার পরামর্শ দেওয়া হয়।
নিম্নলিখিত অ্যান্ড্রয়েড ডিবাগ ব্রিজ (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