محدودیت های سیستم در کار پس زمینه

فرآیندهای پس‌زمینه می‌توانند حافظه و باتری زیادی داشته باشند. برای مثال، یک پخش ضمنی ممکن است بسیاری از فرآیندهای پس‌زمینه‌ای را که برای گوش دادن به آن ثبت‌نام کرده‌اند، شروع کند، حتی اگر این فرآیندها کار زیادی انجام ندهند. این می تواند تأثیر قابل توجهی بر عملکرد دستگاه و تجربه کاربر داشته باشد.

برای جلوگیری از محدودیت های سیستم، مطمئن شوید که از API مناسب برای کار پس زمینه خود استفاده می کنید. مستندات نمای کلی وظایف پس‌زمینه به شما کمک می‌کند API مناسبی را برای نیازهای خود انتخاب کنید.

محدودیت های ایجاد شده توسط کاربر

اگر برنامه‌ای برخی از رفتارهای بد شرح داده شده در Android vitals را نشان دهد، سیستم از کاربر می‌خواهد دسترسی آن برنامه به منابع سیستم را محدود کند.

اگر سیستم متوجه شود که برنامه ای منابع بیش از حد مصرف می کند، به کاربر اطلاع می دهد و به کاربر این امکان را می دهد که اقدامات برنامه را محدود کند. رفتارهایی که می توانند باعث ایجاد اخطار شوند عبارتند از:

  1. Wake lock های بیش از حد : 1 قفل نیمه فعال به مدت یک ساعت در حالت خاموش بودن صفحه نمایش نگه داشته می شود
  2. خدمات پس‌زمینه بیش از حد : اگر برنامه سطوح API کمتر از 26 را هدف قرار می‌دهد و خدمات پس‌زمینه زیادی دارد

محدودیت های دقیق اعمال شده توسط سازنده دستگاه تعیین می شود. برای مثال، در ساخت‌های 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 گوش دهند. با این حال، ConnectivityManager API روش قوی تری برای درخواست پاسخ به تماس تنها زمانی که شرایط شبکه مشخص شده برآورده می شود، ارائه می دهد.

اشیاء 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 های تغییر یافته بیشتر از 50 باشد، خالی است.

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های زمان‌بندی کار مراجعه کنید.