فرآیندهای پسزمینه میتوانند مصرف حافظه و باتری بالایی داشته باشند. برای مثال، یک پخش ضمنی ممکن است بسیاری از فرآیندهای پسزمینه را که برای گوش دادن به آن ثبتنام کردهاند، شروع کند، حتی اگر آن فرآیندها کار زیادی انجام ندهند. این میتواند تأثیر قابل توجهی بر عملکرد دستگاه و تجربه کاربر داشته باشد.
برای جلوگیری از محدودیتهای سیستم، مطمئن شوید که از API مناسب برای وظیفه پسزمینه خود استفاده میکنید. مستندات مرور کلی وظایف پسزمینه به شما کمک میکند تا API مناسب را برای نیازهای خود انتخاب کنید.
محدودیتهای اعمالشده توسط کاربر
اگر برنامهای برخی از رفتارهای بد شرح داده شده در Android Vitals را از خود نشان دهد، سیستم از کاربر میخواهد دسترسی آن برنامه به منابع سیستم را محدود کند.
اگر سیستم متوجه شود که یک برنامه منابع زیادی را مصرف میکند، به کاربر اطلاع میدهد و به او امکان محدود کردن اقدامات برنامه را میدهد. رفتارهایی که میتوانند باعث ایجاد این اخطار شوند عبارتند از:
- قفلهای بیدارباش بیش از حد : ۱ قفل بیدارباش جزئی که به مدت یک ساعت هنگام خاموش بودن صفحه نمایش نگه داشته میشود
- سرویسهای پسزمینه بیش از حد : اگر برنامه سطوح API پایینتر از ۲۶ را هدف قرار دهد و سرویسهای پسزمینه بیش از حد داشته باشد.
محدودیتهای دقیق اعمالشده توسط سازنده دستگاه تعیین میشوند. برای مثال، در نسخههای AOSP، برنامههای محدودشده نمیتوانند کارها را اجرا کنند، آلارمها را فعال کنند یا از شبکه استفاده کنند، مگر اینکه برنامه در پیشزمینه باشد.
محدودیتهای دریافت پخشهای فعالیت شبکه
اگر برنامهها در مانیفست خود برای دریافت اعلانهای CONNECTIVITY_ACTION ثبتنام کنند، آنها را دریافت نمیکنند و فرآیندهایی که به این اعلان وابسته هستند، شروع نمیشوند. این میتواند برای برنامههایی که میخواهند به تغییرات شبکه گوش دهند یا فعالیتهای شبکهای انبوهی را هنگام اتصال دستگاه به یک شبکه بدون محدودیت زمانی انجام دهند، مشکل ایجاد کند. چندین راهحل برای دور زدن این محدودیت در چارچوب اندروید وجود دارد، اما انتخاب راهحل مناسب به هدفی که میخواهید برنامه شما انجام دهد بستگی دارد.
برنامهریزی برای کار روی اتصالات بدون کنتور
هنگام ساخت یک WorkRequest ، یک Constraint NetworkType.UNMETERED اضافه کنید.
fun scheduleWork(context: Context) {
val workManager = WorkManager.getInstance(context)
val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build()
)
.build()
workManager.enqueue(workRequest)
}
وقتی شرایط لازم برای کار شما فراهم شد، برنامه شما یک فراخوانی برای اجرای متد doWork() در کلاس Worker مشخص شده دریافت میکند.
نظارت بر اتصال شبکه در حین اجرای برنامه
برنامههایی که در حال اجرا هستند، همچنان میتوانند با یک BroadcastReceiver ثبتشده به CONNECTIVITY_CHANGE گوش دهند. با این حال، API ConnectivityManager روشی قویتر برای درخواست فراخوانی مجدد تنها در صورت برآورده شدن شرایط مشخصشده در شبکه ارائه میدهد.
اشیاء NetworkRequest پارامترهای تابع فراخوانی شبکه را بر اساس NetworkCapabilities تعریف میکنند. شما اشیاء NetworkRequest با کلاس NetworkRequest.Builder ایجاد میکنید. registerNetworkCallback سپس شیء NetworkRequest را به سیستم ارسال میکند. هنگامی که شرایط شبکه برآورده شد، برنامه یک تابع فراخوانی برای اجرای متد onAvailable() تعریف شده در کلاس ConnectivityManager.NetworkCallback خود دریافت میکند.
برنامه تا زمانی که از برنامه خارج نشود یا تابع unregisterNetworkCallback() را فراخوانی نکند، به دریافت فراخوانیهای برگشتی ادامه میدهد.
محدودیت در دریافت تصاویر و ویدیوهای ارسالی
برنامهها قادر به ارسال یا دریافت پخشهای ACTION_NEW_PICTURE یا ACTION_NEW_VIDEO نیستند. این محدودیت به کاهش تأثیرات بر عملکرد و تجربه کاربر در زمانی که چندین برنامه باید برای پردازش یک تصویر یا ویدیوی جدید فعال شوند، کمک میکند.
مشخص کنید کدام مراجع محتوا باعث ایجاد مشکل شدهاند
WorkerParameters به برنامه شما اجازه میدهد تا اطلاعات مفیدی در مورد اینکه کدام منابع محتوا و URIها باعث شروع کار شدهاند، دریافت کند:
List<Uri> getTriggeredContentUris()
لیستی از URI هایی که کار را آغاز کردهاند، برمیگرداند. اگر هیچ URI کار را آغاز نکرده باشد (مثلاً کار به دلیل مهلت یا دلیل دیگری آغاز شده باشد)، یا تعداد URI های تغییر یافته بیش از ۵۰ باشد، این مقدار خالی است.
List<String> getTriggeredContentAuthorities()
یک لیست رشتهای از منابع محتوایی که کار را آغاز کردهاند، برمیگرداند. اگر لیست برگردانده شده خالی نباشد، getTriggeredContentUris() برای بازیابی جزئیات اینکه کدام URIها تغییر کردهاند، استفاده کنید.
کد نمونه زیر متد CoroutineWorker.doWork() را لغو میکند و مجوزهای محتوا و URIهایی را که کار را آغاز کردهاند، ثبت میکند:
class MyWorker(
appContext: Context,
params: WorkerParameters
): CoroutineWorker(appContext, params)
override suspend fun doWork(): Result {
StringBuilder().apply {
append("Media content has changed:\n")
params.triggeredContentAuthorities
.takeIf { it.isNotEmpty() }
?.let { authorities ->
append("Authorities: ${authorities.joinToString(", ")}\n")
append(params.triggeredContentUris.joinToString("\n"))
} ?: append("(No content)")
Log.i(TAG, toString())
}
return Result.success()
}
}
تست برنامه تحت محدودیتهای سیستم
بهینهسازی برنامههای شما برای اجرا در دستگاههای با حافظه کم یا در شرایط کمبود حافظه، میتواند عملکرد و تجربه کاربری را بهبود بخشد. حذف وابستگیها به سرویسهای پسزمینه و گیرندههای پخش ضمنی ثبتشده در مانیفست میتواند به اجرای بهتر برنامه شما در چنین دستگاههایی کمک کند. توصیه میشود برنامه خود را طوری بهینهسازی کنید که بدون استفاده کامل از این فرآیندهای پسزمینه اجرا شود.
برخی از دستورات اضافی Android Debug Bridge (ADB) میتوانند به شما در آزمایش رفتار برنامه با غیرفعال بودن آن فرآیندهای پسزمینه کمک کنند:
برای شبیهسازی شرایطی که پخشهای ضمنی و سرویسهای پسزمینه در دسترس نیستند، دستور زیر را وارد کنید:
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignoreبرای فعال کردن مجدد پخشهای ضمنی و سرویسهای پسزمینه، دستور زیر را وارد کنید:
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
برنامه خود را بیشتر بهینه کنید
برای سایر روشهای خوب برای بهینهسازی رفتار وظایف پسزمینه، به مستندات APIهای «بهینهسازی مصرف باتری برای زمانبندی وظایف» مراجعه کنید.