Optymalizacja w tle

Procesy w tle mogą pochłaniać dużo pamięci i baterii. Na przykład niejawna transmisja może uruchomić w tle wiele procesów, które zarejestrowały Wysłuchać ich, nawet jeśli te procesy nie przyniosą zbyt wiele korzyści. Może mieć mają duży wpływ na wydajność urządzenia i wrażenia użytkownika.

Aby rozwiązać ten problem, Android 7.0 (poziom interfejsu API 24) stosuje te zasady ograniczenia:

Jeśli Twoja aplikacja używa któregoś z tych intencji, usuń zależności od nich jak najszybciej, aby móc prawidłowo kierować reklamy na urządzenia z Androidem 7.0 lub wyższą. Platforma Androida udostępnia kilka rozwiązań, które pozwalają zminimalizować na potrzeby tych niejawnych komunikatów. Na przykład: JobScheduler i nowy menedżer WorkManager udostępnia zaawansowane mechanizmy planowania sieci w przypadku określonych warunków, na przykład połączenia z siecią bez pomiaru są spełnione. Teraz możesz też używać JobScheduler na zmiany dostawców treści. JobInfo obiekty zawierają parametry, które JobScheduler aby zaplanować zadanie. Po spełnieniu warunków zadania system wykonuje to zadanie na zasobie JobService Twojej aplikacji.

Na tej stronie dowiemy się, jak używać metod alternatywnych, takich jak JobScheduler, aby dostosować aplikację do nowych ograniczeń.

Ograniczenia inicjowane przez użytkownika

Na stronie Wykorzystanie baterii w systemie użytkownik może wybierz jedną z następujących opcji:

  • Bez ograniczeń: zezwala na pracę w tle, co może zużywać więcej baterii.
  • Zoptymalizowane (ustawienie domyślne): optymalizacja działania aplikacji w tle, na podstawie interakcji użytkownika z aplikacją.
  • Z ograniczonym dostępem:całkowicie uniemożliwia aplikacji działanie w tle. aplikacji; może nie działać zgodnie z oczekiwaniami.
.

Jeśli aplikacja wykazuje pewne działania opisane w sekcji Android Android Vitals, system może poprosić użytkownika o ograniczenie dostępu aplikacji do zasobów systemowych.

Jeśli system zauważy, że aplikacja zużywa zbyt dużo zasobów, i pozwala mu ograniczyć działania w aplikacji. Działania, które mogą spowodować wyświetlenie powiadomienia, to między innymi:

  • Nadmierne blokady uśpienia: jedna częściowa blokada uśpienia zatrzymana na godzinę przy wyłączonym ekranie
  • Nadmierne usługi w tle: jeśli aplikacja jest kierowana na interfejsy API niższe niż 26 i ma nadmierna liczba usług w tle

Dokładne ograniczenia są określane przez producenta urządzenia. Dla: na przykład w kompilacjach AOSP z Androidem 9 (poziom interfejsu API 28) lub nowszym działające w tle, które są objęte „ograniczonym” mają te elementy Ograniczenia:

  • Nie udało się uruchomić usług działających na pierwszym planie
  • Istniejące usługi na pierwszym planie zostaną usunięte
  • Alarmy nie są wywoływane
  • Zadania nie są wykonywane

Poza tym, jeśli aplikacja jest kierowana na Androida 13 (poziom interfejsu API 33) lub nowszego i jest „z ograniczeniami” system nie przesyła komunikatu BOOT_COMPLETED lub komunikat LOCKED_BOOT_COMPLETED do momentu uruchomienia aplikacji na innych urządzeniach .

Konkretne ograniczenia są wymienione tutaj Ograniczenia dotyczące zarządzania energią.

Ograniczenia odbierania komunikatów o aktywności w sieci

Aplikacje kierowane na Androida 7.0 (poziom interfejsu API 24) nie otrzymują transmisji CONNECTIVITY_ACTION, jeśli zarejestrować się, aby otrzymać je w swoim pliku manifestu, oraz procesy zależne od tego transmisja nie rozpocznie się. Może to stanowić problem w przypadku aplikacji, które chcą nasłuchiwania zmian w sieci lub wykonywania działań zbiorczych w sieci, gdy łączy się z siecią bez pomiaru. Kilka rozwiązań, które pozwalają obejść ten problem na platformie Androida są już pewne ograniczenia, ale warto wybrać zależy od tego, co chcesz osiągnąć dzięki aplikacji.

Uwaga: BroadcastReceiver zarejestrowana w Context.registerReceiver() będzie nadal odbierać te komunikaty, gdy aplikacja jest uruchomiona.

Zaplanuj zadania sieciowe w przypadku połączeń bez pomiaru użycia danych

Jeśli używasz klasy JobInfo.Builder aby utworzyć obiekt JobInfo, zastosuj metodę setRequiredNetworkType() i przekaż JobInfo.NETWORK_TYPE_UNMETERED jako parametr zadania. Następujący przykładowy kod planuje uruchomienie usługi, gdy urządzenie łączy się z siecią bez pomiaru sieci i trwa jej ładowanie:

Kotlin

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

Java

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

Po spełnieniu warunków zadania aplikacja otrzymuje wywołanie zwrotne w celu jej uruchomienia metody onStartJob() w funkcji określono JobService.class. Więcej przykładów implementacji funkcji JobScheduler znajdziesz w przykładowej aplikacji JoobScheduler.

Nową alternatywą dla JobScheduler jest WorkManager – interfejs API umożliwiający planowanie zadania w tle, które wymagają gwarantowane zakończenie niezależnie od tego, czy proces aplikacji jest w toku, czy nie. Menedżer roboczy wybiera odpowiedni sposób wykonania pracy (bezpośrednio w wątku w procesie aplikacji jako a także z JobScheduler, FirebaseJobDispatcher czy AlarmManagera) na podstawie takich czynników jak poziomu interfejsu API urządzenia. Oprócz tego WorkManager nie wymaga Usług Google Play i zapewnia kilka zaawansowanych funkcji, takich jak łączenie zadań ze sobą lub sprawdzanie ich stanu. Aby się uczyć Więcej informacji znajdziesz w sekcji WorkManager.

Monitorowanie połączeń sieciowych podczas działania aplikacji

Włączone aplikacje mogą nadal nasłuchiwać przez CONNECTIVITY_CHANGE przy użyciu zarejestrowano BroadcastReceiver. Interfejs ConnectivityManager API zapewnia jednak bardziej niezawodną metodę wysyłania żądań wywołanie zwrotne tylko po spełnieniu określonych warunków sieciowych.

Obiekty NetworkRequest definiują parametry funkcji wywołanie zwrotne sieci (NetworkCapabilities). Ty tworzyć obiekty NetworkRequest z klasą NetworkRequest.Builder. registerNetworkCallback() a następnie przekazuje obiekt NetworkRequest do systemu. Kiedy jeśli warunki sieciowe są spełnione, aplikacja otrzymuje wywołanie zwrotne w celu wykonania Metoda onAvailable() zdefiniowana w klasie ConnectivityManager.NetworkCallback.

Aplikacja będzie otrzymywać wywołania zwrotne, dopóki nie zostanie zamknięta lub nie nawiąże połączenia. unregisterNetworkCallback()

Ograniczenia dotyczące odbierania obrazów i transmisji wideo

Na Androidzie 7.0 (poziom interfejsu API 24) aplikacje nie mogą wysyłać ani odbierać transmisji ACTION_NEW_PICTURE ani ACTION_NEW_VIDEO. To ograniczenie pomaga zmniejszać wpływ na wydajność i wygodę użytkowników, gdy konieczne jest wybudzenia, żeby przetworzyć nowy obraz lub film. Android 7.0 (poziom API 24) Rozszerza zakres JobInfo i JobParameters, aby zapewnić alternatywne rozwiązanie.

Aktywuj zadania w przypadku zmian identyfikatora URI treści

Aby aktywować zadania po zmianie identyfikatora URI treści, Android 7.0 (poziom API 24) rozszerzył API JobInfo za pomocą tych metod:

JobInfo.TriggerContentUri()
Obejmuje parametry wymagane do aktywowania zadania po zmianie identyfikatora URI treści.
JobInfo.Builder.addTriggerContentUri()
Przekazuje obiekt TriggerContentUri do JobInfo. ContentObserver monitoruje zawarty w niej identyfikator URI treści. Jeśli z zadaniem powiązanych jest wiele obiektów TriggerContentUri, system udostępni funkcję wywołanie zwrotne, nawet jeśli zgłasza zmianę tylko jednego z identyfikatorów URI treści.
.
Dodaj flagę TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS do wyzwalać zadanie, jeśli zmienią się dowolne elementy podrzędne danego identyfikatora URI. Ta flaga odpowiada parametrowi notifyForDescendants przekazanemu do registerContentObserver().

Uwaga: TriggerContentUri() nie można używać w tych krajach: w połączeniu z wartością setPeriodic() lub setPersisted(). Aby stale monitorować zmiany w treści, zaplanuj nowy JobInfo przed zakończeniem obsługi ostatniego wywołania zwrotnego przez aplikację JobService.

Ten przykładowy kod zaplanuje uruchomienie zadania, gdy system zgłosi zmiana identyfikatora URI treści (MEDIA_URI):

Kotlin

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

Java

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

Gdy system zgłosi zmianę określonych identyfikatorów URI treści, aplikacja otrzymuje wywołanie zwrotne, a obiekt JobParameters jest przekazano do onStartJob() w komórce MediaContentJob.class.

Sprawdzanie, które organizacje zajmujące się treścią aktywowały zadanie

Android 7.0 (poziom interfejsu API 24) rozszerza też JobParameters na pozwalają aplikacji otrzymywać przydatne informacje o urzędach certyfikacji, i identyfikatory URI uruchomiły zadanie:

Uri[] getTriggeredContentUris()
Zwraca tablicę identyfikatorów URI, które aktywowały zadanie. Wartość to null, jeśli żaden z identyfikatorów URI nie uruchomił zadania (na przykład zadanie zostało spowodowane ze względu na termin lub inną przyczynę) albo liczbę zmienionych Identyfikatory URI mają więcej niż 50.
String[] getTriggeredContentAuthorities()
Zwraca tablicę ciągów znaków urzędów treści, które aktywowały zadanie. Jeśli zwrócona tablica nie jest wartością null, użyj getTriggeredContentUris() aby uzyskać szczegółowe informacje o zmienionych identyfikatorach URI.

Poniższy przykładowy kod zastępuje metodę JobService.onStartJob() i rejestruje urzędy treści i identyfikatory URI, które spowodowały uruchomienie zadania:

Kotlin

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
}

Java

@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;
}

Dalsza optymalizacja aplikacji

optymalizowanie aplikacji pod kątem działania na urządzeniach z małą ilością pamięci lub jej małą ilością pamięci; warunki, może poprawić wydajność i wygodę użytkowników. Usuwam zależności od usług w tle i niejawnie zarejestrowane w pliku manifestu odbiorniki mogą pomóc w lepszym działaniu aplikacji na takich urządzeniach. Chociaż Android 7.0 (poziom interfejsu API 24) podejmuje działania, by ograniczyć niektóre z tych problemów. zalecamy zoptymalizowanie aplikacji tak, aby działała bez użycia tych w tle.

Następujący Android Debug Bridge (ADB): umożliwiają przetestowanie działania aplikacji przy wyłączonych procesach w tle:

  • Symulowanie warunków, w których niejawne transmisje i usługi w tle są niedostępne, wpisz następujące polecenie:
  • $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore
    
  • Aby ponownie włączyć niejawne transmisje i usługi w tle, wpisz to polecenie:
  • $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
    
  • Możesz symulować umieszczanie aplikacji przez użytkownika jako „objęte ograniczeniami” stan dla wykorzystanie baterii w tle. To ustawienie uniemożliwia uruchamianie aplikacji w tle. Aby to zrobić, uruchom następujące polecenie w oknie terminala:
  • $ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny