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. Może to mieć znaczny wpływ na wydajność urządzenia i wygodę użytkowników.

Aby rozwiązać ten problem, w Androidzie 7.0 (poziom interfejsu API 24) obowiązują te ograniczenia:

Jeśli Twoja aplikacja używa któregoś z tych intencji, jak najszybciej usuń te zależności, aby móc odpowiednio kierować reklamy na urządzenia z Androidem 7.0 lub nowszym. Platforma Android oferuje kilka rozwiązań, które ograniczają potrzebę korzystania z tych niejawnych transmisji. Na przykład JobScheduler i nowy WorkManager zapewniają niezawodne mechanizmy do planowania operacji sieciowych, gdy spełnione są określone warunki, takie jak połączenie z siecią bez limitu danych. Teraz możesz też używać JobScheduler na zmiany dostawców treści. JobInfo obiekty zawierają parametry, które JobScheduler aby zaplanować zadanie. Gdy warunki zadania zostaną spełnione, system wykona to zadanie w Twojej aplikacji JobService.

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 Użycie baterii w ustawieniach systemu użytkownik może wybrać jedną z tych opcji:

  • Nieograniczone: zezwalaj na wszystkie działania w tle, które mogą zużywać więcej baterii.
  • Zoptymalizowana (domyślnie): optymalizuje działanie aplikacji w tle na podstawie interakcji użytkownika z aplikacją.
  • Ograniczone: 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 nadmierne zasoby, powiadomi użytkownika i zaoferuje mu możliwość ograniczenia działań aplikacji. Działania, które mogą spowodować wyświetlenie powiadomienia, to między innymi:

  • Zbyt wiele blokad uśpienia: 1 częściowa blokada uśpienia utrzymana przez godzinę, gdy ekran jest wyłączony
  • 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 można uruchomić usług na pierwszym planie
  • Istniejące usługi na pierwszym planie zostaną usunięte
  • Alarmy nie są aktywowane
  • Zadania nie są wykonywane

Jeśli aplikacja jest kierowana na Androida 13 (API na poziomie 33) lub nowszego i jest w stanie „ograniczony”, system nie dostarcza transmisji BOOT_COMPLETED ani LOCKED_BOOT_COMPLETED, dopóki aplikacja nie zostanie uruchomiona z innych powodów.

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

Ograniczenia dotyczące odbierania transmisji aktywności 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 dla aplikacji, które chcą nasłuchiwać zmian w sieci lub wykonywać zbiorcze działania sieciowe, gdy urządzenie łączy się z siecią bez limitu. Kilka rozwiązań, które pomagają ominąć 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.

Planowanie zadań sieciowych na połączeniach bezpłatnych

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:

KotlinJava
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)
}
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, który umożliwia planowanie zadań w tle, które wymagają gwarantowanego ukończenia, niezależnie od tego, czy proces aplikacji jest uruchomiony. Menedżer pracy 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łączenia z internetem podczas działania aplikacji

Uruchomione aplikacje mogą nadal nasłuchiwać CONNECTIVITY_CHANGE z zarejestrowanym 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 wywołania zwrotnego sieci w terminach 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 wywoła funkcji unregisterNetworkCallback().

Ograniczenia dotyczące odbierania obrazów i transmisji wideo

W Androidzie 7.0 (interfejs API na poziomie 24) aplikacje nie mogą wysyłać ani odbierać transmisji ACTION_NEW_PICTURE ani ACTION_NEW_VIDEO. To ograniczenie pomaga ograniczyć wpływ na wydajność i wrażenia użytkownika, gdy kilka aplikacji musi się aktywować, aby przetworzyć nowy obraz lub film. Android 7.0 (poziom interfejsu API 24) rozszerza JobInfoJobParameters, 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. ContentObservermonitoruje zakapsułowany identyfikator URI treści. Jeśli z zadaniem powiązanych jest wiele obiektów TriggerContentUri, system wywołuje funkcję zwrotną, nawet jeśli zgłosi 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. Ten parametr odpowiada parametrowi notifyForDescendants przekazanemu do funkcji registerContentObserver().

Uwaga: TriggerContentUri() nie można używać w tych krajach: w połączeniu z wartością setPeriodic() lub setPersisted(). Aby stale sprawdzać, czy nie nastąpiły zmiany treści, zaplanuj nowe JobInfo, zanim funkcja JobService w aplikacji zakończy obsługę ostatniego wywołania zwrotnego.

Poniższy przykładowy kod powoduje uruchomienie zadania, gdy system zgłosi zmianę identyfikatora URI treści, MEDIA_URI:

KotlinJava
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)
}
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ę w wybranych identyfikatorach URI treści, Twoja aplikacja otrzyma wywołanie zwrotne, a obiekt JobParameters zostanie przekazany metodzie onStartJob()MediaContentJob.class.

Określanie, które instytucje zajmujące się treściami wywołał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 wywołały zadanie. Będzie to null, jeśli żadne adresy URI nie zostały uruchomione (na przykład zadanie zostało uruchomione z powodu terminu lub z innego powodu) albo jeśli liczba zmienionych adresów URI jest większa niż 50.
String[] getTriggeredContentAuthorities()
Zwraca tablicę ciągów znaków z autorytetami treści, które wywołał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:

KotlinJava
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
}
@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:

  • Aby symulować warunki, w których transmisje niejawne i usługi w tle są niedostępne, wpisz to polecenie:
  • $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore
    
  • Aby ponownie włączyć transmisje i usługi w tle, wpisz to polecenie:
  • $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
    
  • Możesz symulować sytuację, w której użytkownik ustawia stan „Ograniczone” dla wykorzystania baterii w tle w Twojej aplikacji. To ustawienie uniemożliwia uruchamianie aplikacji w tle. Aby to zrobić, uruchom w oknie terminala to polecenie:
  • $ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny