Ograniczenia systemowe dotyczące działania w tle

Procesy w tle mogą wymagać dużo pamięci i baterii. Na przykład transmisja niejawna może uruchamiać wiele procesów w tle, które ją nasłuchują, nawet jeśli nie są one zbyt pracochłonne. Może to mieć duży wpływ zarówno na wydajność urządzenia, jak i wrażenia użytkowników.

Aby uniknąć ograniczeń systemu, upewnij się, że do zadania w tle używasz odpowiedniego interfejsu API. Dokumentacja Przegląd zadań w tle pomoże Ci wybrać interfejs API odpowiedni do Twoich potrzeb.

Ograniczenia inicjowane przez użytkownika

Jeśli aplikacja wykazuje niektóre z niewłaściwych działań opisanych w Android Vitals, system poprosi użytkownika o ograniczenie jej dostępu do zasobów systemowych.

Jeśli system wykryje, że aplikacja zużywa nadmiarowe zasoby, powiadomi o tym użytkownika i umożliwi ograniczenie działań w aplikacji. Działania, które mogą wywołać takie powiadomienie:

  1. Nadmierna blokada uśpienia: 1 częściowa blokada wybudzania utrzymywana na godzinę przy wyłączonym ekranie
  2. Nadmierna liczba usług w tle: jeśli aplikacja jest kierowana na poziomy API niższe niż 26 i ma za dużo usług w tle.

Dokładne ograniczenia są określane przez producenta urządzenia. Na przykład w kompilacjach AOSP aplikacje z ograniczonym dostępem nie mogą uruchamiać zadań, uruchamiać alarmów ani używać sieci, chyba że działa ona na pierwszym planie.

Ograniczenia w odbieraniu komunikatów o aktywności w sieci

Aplikacje nie otrzymują komunikatów CONNECTIVITY_ACTION, jeśli zarejestrują się, by otrzymywać je w pliku manifestu, a procesy zależne od tej transmisji nie będą się uruchamiać. Może to powodować problemy w przypadku aplikacji, które chcą nasłuchiwać zmian w sieci lub wykonywać zbiorcze działania sieciowe, gdy urządzenie łączy się z siecią bez pomiaru. Istnieje już kilka rozwiązań, które pozwalają ominąć to ograniczenie, ale wybór odpowiedniego zależy od tego, co chcesz osiągnąć przez aplikację.

Planowanie pracy przy połączeniach bez pomiaru

Podczas tworzenia obiektu WorkRequest dodaj NetworkType.UNMETERED Constraint.

fun scheduleWork(context: Context) {
    val workManager = WorkManager.getInstance(context)
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
       .setConstraints(
           Constraints.Builder()
               .setRequiredNetworkType(NetworkType.UNMETERED)
               .build()
           )
       .build()

    workManager.enqueue(workRequest)
}

Gdy zostaną spełnione warunki Twojej pracy, aplikacja otrzyma wywołanie zwrotne, które uruchomi metodę doWork() w określonej klasie Worker.

Monitoruj połączenia sieciowe, gdy aplikacja jest uruchomiona

Aktywne aplikacje mogą nadal nasłuchiwać na CONNECTIVITY_CHANGE przy zarejestrowanych urządzeniach (BroadcastReceiver). Interfejs API ConnectivityManager zapewnia jednak bardziej niezawodną metodę żądania wywołania zwrotnego tylko w przypadku spełnienia określonych warunków sieciowych.

Obiekty NetworkRequest definiują parametry wywołania zwrotnego sieci w oparciu o NetworkCapabilities. Obiekty NetworkRequest tworzysz za pomocą klasy NetworkRequest.Builder. registerNetworkCallback przekazuje obiekt NetworkRequest do systemu. Gdy warunki sieci zostaną spełnione, aplikacja otrzyma wywołanie zwrotne w celu wykonania metody onAvailable() zdefiniowanej w jej klasie ConnectivityManager.NetworkCallback.

Aplikacja będzie otrzymywać wywołania zwrotne, dopóki jej nie zamknie lub nie wywoła wywołania unregisterNetworkCallback().

Ograniczenia w zakresie odbierania transmisji obrazów i filmów

Aplikacje nie mogą wysyłać ani odbierać transmisji ACTION_NEW_PICTURE ani ACTION_NEW_VIDEO. To ograniczenie pomaga złagodzić wydajność i wrażenia użytkowników, gdy kilka aplikacji musi się wybudzić, aby przetworzyć nowy obraz lub film.

Ustalenie, które organy ochrony treści spowodowały podjęcie pracy

WorkerParameters umożliwia aplikacji otrzymywanie przydatnych informacji o urzędach treści i identyfikatorach URI, które spowodowały wykonanie zadania:

List<Uri> getTriggeredContentUris()

Zwraca listę identyfikatorów URI, które spowodowały uruchomienie zadania. To pole jest puste, jeśli żaden identyfikator URI nie uruchomił działania (np. utwór został rozpoczęty z powodu określonego terminu lub z innego powodu) lub liczba zmienionych identyfikatorów URI przekracza 50.

List<String> getTriggeredContentAuthorities()

Zwraca ciąg znaków w postaci ciągów znaków, które wywołały dany utwór. Jeśli zwrócona lista nie jest pusta, użyj funkcji getTriggeredContentUris(), aby pobrać szczegóły dotyczące zmienionych identyfikatorów URI.

Ten przykładowy kod zastępuje metodę CoroutineWorker.doWork() i rejestruje urzędy treści oraz identyfikatory URI, które spowodowały uruchomienie zadania:

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

Przetestuj aplikację pod ograniczeniami systemu

Optymalizacja aplikacji pod kątem działania na urządzeniach z małą ilością pamięci lub przy małej ilości pamięci może poprawić wydajność i wygodę użytkowników. Usunięcie zależności od usług działających w tle i ukrytych odbiorników transmisji zarejestrowanych w pliku manifestu może poprawić działanie aplikacji na takich urządzeniach. Zalecamy zoptymalizowanie aplikacji pod kątem całkowitego działania bez tych procesów w tle.

Niektóre dodatkowe polecenia Android Debug Bridge (ADB) mogą pomóc w przetestowaniu działania aplikacji przy wyłączonych procesach w tle:

  • Aby symulować warunki, w których nie są dostępne niejawne komunikaty i usługi w tle, wpisz to polecenie:

    $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore

  • Aby ponownie włączyć niejawne komunikaty i usługi w tle, wpisz to polecenie:

    $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow

Dalsza optymalizacja aplikacji

Inne dobre sposoby na optymalizację działania zadań w tle znajdziesz w dokumentacji Optymalizacji wykorzystania baterii przez interfejsy API harmonogramu zadań.