Ciągłe częściowe blokady uśpienia

Częściowe blokady uśpienia to mechanizm w interfejsie API PowerManager, który umożliwia programistom utrzymanie procesora po wyłączeniu wyświetlacza urządzenia (z powodu przekroczenia czasu oczekiwania systemu lub naciśnięcia przez użytkownika przycisku zasilania). Aplikacja uzyskuje częściową blokadę uśpienia, wywołując metodę acquire() z flagą PARTIAL_WAKE_LOCK. Częściowa blokada uśpienia utknie się na dłuższy czas, gdy aplikacja działa w tle (żadna część aplikacji nie będzie widoczna dla użytkownika). Ten warunek wyczerpuje baterię, ponieważ zapobiega przełączaniu się w niższy stan zasilania. Częściowych blokad uśpienia należy używać tylko w razie potrzeby, a gdy już nie są potrzebne, zwalać je z pamięci.

Jeśli w Twojej aplikacji występuje przerwa częściowa blokada uśpienia, skorzystaj ze wskazówek na tej stronie, aby zdiagnozować i rozwiązać problem.

Wykryj problem

Nie zawsze wiesz, że częściowe blokady uśpienia aplikacji utknęły. Jeśli masz już opublikowaną aplikację, Android Vitals może pomóc Ci zidentyfikować problem.

Android Vitals

Android Vitals może poprawić wydajność aplikacji, powiadamiając Cię w Konsoli Play o ciągłych, częściowych blokadach uśpienia. Android Vitals zgłasza częściowe blokady uśpienia jako ciągłe, które trwają co najmniej godzinę, a podczas działania w tle częściowa blokada uśpienia występuje w ramach sesji baterii.

Definicja sesji baterii zależy od wersji platformy.

  • W Androidzie 10 sesja baterii to zbiór wszystkich raportów o stanie baterii, które zostały odebrane w ciągu danego 24-godzinnego okresu. Raport o stanie baterii odnosi się do okresu między dwoma ładowaniami baterii od poziomu naładowania poniżej 20% do powyżej 80% lub od dowolnego poziomu naładowania do 100%.
  • W Androidzie 11 sesja baterii ma stałą długość 24 godzin.

Wyświetlona liczba sesji baterii jest sumą danych wszystkich mierzonych użytkowników aplikacji. Więcej informacji o tym, jak Google Play gromadzi dane Android Vitals, znajdziesz w dokumentacji Konsoli Play.

Gdy dowiesz się, że w aplikacji występuje nadmierna liczba ciągłych częściowych blokad uśpienia, następnym krokiem jest rozwiązanie problemu.

Rozwiąż problem

Blokady uśpienia wprowadziliśmy we wczesnych wersjach platformy Android, ale z czasem wiele przypadków użycia, które wcześniej wymagały blokady uśpienia, jest teraz lepiej obsługiwanych przez nowsze interfejsy API, takie jak WorkManager.

Ta sekcja zawiera wskazówki dotyczące rozwiązywania problemów z blokadami uśpienia, ale w dłuższej perspektywie rozważ przeniesienie aplikacji zgodnie z zaleceniami podanymi w sekcji Sprawdzone metody.

Znajdź i popraw miejsca w kodzie, w których występuje blokada uśpienia, np. wywołania podklas newWakeLock(int, String) lub WakefulBroadcastReceiver. Oto kilka wskazówek:

  • Zalecamy umieszczenie nazwy pakietu, klasy lub metody w nazwie tagu wybudzenia, aby łatwo zidentyfikować lokalizację w źródle, w której została utworzona blokada uśpienia. Oto kilka dodatkowych wskazówek:
    • Pomiń w nazwie użytkownika wszelkie informacje umożliwiające identyfikację, np. adres e-mail. W przeciwnym razie zamiast nazwy blokady uśpienia urządzenie rejestruje _UNKNOWN.
    • Nie pobieraj nazwy klasy ani metody automatycznie, np. przez wywołanie getName(), ponieważ Proguard może ją zaciemnić. Zamiast tego użyj zakodowanego na stałe ciągu znaków.
    • Nie dodawaj licznika ani unikalnych identyfikatorów do tagów blokady uśpienia. System nie będzie w stanie agregować blokad uśpienia utworzonych tą samą metodą, ponieważ wszystkie one mają unikalne identyfikatory.
  • Upewnij się, że kod uwalnia wszystkie uzyskane blokady uśpienia. To trudniejsze niż sprawdzanie, czy każde wywołanie do acquire() ma odpowiadające mu wywołanie do metody release(). Oto przykład blokady uśpienia, która nie jest zwalniana z powodu niewykrytego wyjątku:

    Kotlin

    @Throws(MyException::class)
    fun doSomethingAndRelease() {
        wakeLock.apply {
            acquire()
            doSomethingThatThrows()
            release()  // does not run if an exception is thrown
        }
    }

    Java

        void doSomethingAndRelease() throws MyException {
            wakeLock.acquire();
            doSomethingThatThrows();
            wakeLock.release();  // does not run if an exception is thrown
        }

    Oto prawidłowa wersja tego kodu:

    Kotlin

    @Throws(MyException::class)
    fun doSomethingAndRelease() {
        wakeLock.apply {
            try {
                acquire()
                doSomethingThatThrows()
            } finally {
                release()
            }
        }
    }

    Java

        void doSomethingAndRelease() throws MyException {
            try {
                wakeLock.acquire();
                doSomethingThatThrows();
            } finally {
                wakeLock.release();
            }
        }
  • Zadbaj o to, aby blokady uśpienia były usuwane, gdy nie są już potrzebne. Jeśli na przykład używasz blokady uśpienia, aby umożliwić dokończenie zadania w tle, dopilnuj, aby działanie to nastąpiło po jego zakończeniu. Jeśli blokada uśpienia będzie utrzymywana dłużej niż oczekiwano bez jej zwolnienia, może to oznaczać, że zadanie w tle trwa dłużej niż zwykle.

Gdy rozwiążesz problem w kodzie, sprawdź, czy Twoja aplikacja prawidłowo udostępnia blokady uśpienia, korzystając z tych narzędzi na Androida:

  • dumpsys – narzędzie udostępniające informacje o stanie usług systemowych na urządzeniu. Aby zobaczyć stan usługi zasilania, w tym listę blokad uśpienia, uruchom adb shell dumpsys power.

  • Historia baterii – narzędzie, które analizuje dane wyjściowe raportu o błędach w Androidzie w postaci wizualnej reprezentacji zdarzeń związanych z zasilaniem.

Sprawdzone metody

Ogólnie aplikacja powinna unikać częściowych blokad uśpienia, ponieważ może to zbyt łatwo rozładować baterię użytkownika. Android zapewnia alternatywne interfejsy API do niemal każdego zastosowania, które wcześniej wymagało częściowej blokady uśpienia. Ostatnim przypadkiem użycia w przypadku częściowych blokad uśpienia jest zapewnienie, że aplikacja muzyczną będzie mogła odtwarzać się nawet wtedy, gdy ekran jest wyłączony. Jeśli używasz blokad uśpienia do uruchamiania zadań, rozważ alternatywne rozwiązania opisane w przewodniku po przetwarzaniu w tle.

Jeśli musisz używać częściowych blokad uśpienia, postępuj zgodnie z tymi zaleceniami:

  • Upewnij się, że część aplikacji jest na pierwszym planie. Jeśli na przykład musisz uruchomić usługę, uruchom ją na pierwszym planie. Informuje to użytkownika o tym, że aplikacja nadal działa.
  • Zasada uzyskiwania i usuwania blokad uśpienia musi być jak najprostsza. Jeśli logika blokady uśpienia jest powiązana ze złożonymi maszynami stanu, limitami czasu, pulami wykonawców lub zdarzeniami wywołania zwrotnego, każdy subtelny błąd w tej logice może powodować dłużej niż zwykle utrzymanie blokady uśpienia. Takie błędy są trudne do zdiagnozowania i debugowania.