Aplikacje na Androida wysyłają i odbierają wiadomości rozgłoszeniowe z systemu Android i innych aplikacji na Androida, podobnie jak w przypadku wzorca projektowego publikowanie-subskrypcja. System i aplikacje zwykle wysyłają transmisje, gdy wystąpią określone zdarzenia. Na przykład system Android wysyła transmisje, gdy występują różne zdarzenia systemowe, takie jak uruchomienie systemu lub ładowanie urządzenia. Aplikacje wysyłają też niestandardowe transmisje, np. aby powiadomić inne aplikacje o czymś, co może je zainteresować (np. o pobraniu nowych danych).
Aplikacje mogą rejestrować się w celu otrzymywania określonych transmisji. Gdy transmisja jest wysyłana, system automatycznie kieruje ją do aplikacji, które subskrybują odbieranie tego konkretnego typu transmisji.
Ogólnie rzecz biorąc, transmisje mogą być używane jako system przesyłania wiadomości w aplikacjach i poza normalnym wzorcem przeglądania. Musisz jednak uważać, aby nie nadużywać możliwości odpowiadania na transmisje i uruchamiania w tle zadań, które mogą przyczyniać się do spowolnienia działania systemu.
Informacje o komunikatach systemowych
System automatycznie wysyła transmisje, gdy występują różne zdarzenia systemowe, np. gdy system przełącza się w tryb samolotowy lub z niego wychodzi. Wszystkie aplikacje, które subskrybują te transmisje,
Obiekt Intent zawiera komunikat. Ciąg znaków action identyfikuje zdarzenie, które wystąpiło, np. android.intent.action.AIRPLANE_MODE. Intencja może też zawierać dodatkowe informacje w polu dodatkowym.
Na przykład intencja trybu samolotowego zawiera dodatkową wartość logiczną, która wskazuje, czy tryb samolotowy jest włączony.
Więcej informacji o odczytywaniu intencji i pobieraniu z niej ciągu działania znajdziesz w artykule Intencje i filtry intencji.
Działania związane z komunikatami systemowymi
Pełną listę działań związanych z komunikatami systemowymi znajdziesz w BROADCAST_ACTIONS.TXTpliku w pakiecie Android SDK. Z każdym działaniem związanym z transmisją jest powiązane pole stałe. Na przykład wartość stałej ACTION_AIRPLANE_MODE_CHANGED to android.intent.action.AIRPLANE_MODE.
Dokumentacja każdego działania związanego z emisją jest dostępna w odpowiednim polu stałej.
Zmiany w komunikatach systemowych
W miarę rozwoju platformy Android okresowo zmienia się sposób działania transmisji systemowych. Aby obsługiwać wszystkie wersje Androida, pamiętaj o tych zmianach:
Android 16
W Androidzie 16 kolejność dostarczania transmisji za pomocą atrybutu android:priority lub IntentFilter.setPriority() w różnych procesach nie będzie gwarantowana. Priorytety transmisji są uwzględniane tylko w ramach tego samego procesu aplikacji, a nie we wszystkich procesach.
Priorytety transmisji są też automatycznie ograniczane do zakresu (SYSTEM_LOW_PRIORITY + 1, SYSTEM_HIGH_PRIORITY – 1).
Tylko komponenty systemu mogą ustawić SYSTEM_LOW_PRIORITY,
SYSTEM_HIGH_PRIORITY jako priorytet transmisji.
Android 14
Gdy aplikacje są w stanie buforowania, system optymalizuje dostarczanie transmisji pod kątem kondycji systemu. Na przykład system odracza mniej ważne transmisje systemowe, takie jak ACTION_SCREEN_ON, gdy aplikacja jest w stanie buforowania.
Gdy aplikacja przejdzie ze stanu buforowanego do aktywnego cyklu życia procesu, system dostarczy wszystkie odroczone transmisje.
Ważne transmisje, które są zadeklarowane w pliku manifestu, tymczasowo usuwają aplikacje ze stanu buforowanego na potrzeby dostarczania.
Android 9
Od Androida 9 (interfejs API na poziomie 28) NETWORK_STATE_CHANGED_ACTION
nie otrzymuje informacji o lokalizacji użytkownika ani danych umożliwiających identyfikację.
Jeśli aplikacja jest zainstalowana na urządzeniu z Androidem 9.0 (poziom API 28) lub nowszym, system nie uwzględnia w transmisjach Wi-Fi identyfikatorów SSID, BSSID, informacji o połączeniu ani wyników skanowania. Aby uzyskać te informacje, zadzwoń pod numer getConnectionInfo().
Android 8.0
Od Androida 8.0 (poziom interfejsu API 26) system nakłada dodatkowe ograniczenia na odbiorniki zadeklarowane w pliku manifestu.
Jeśli Twoja aplikacja jest kierowana na Androida 8.0 lub nowszego, nie możesz używać manifestu do deklarowania odbiornika większości niejawnych transmisji (transmisji, które nie są kierowane konkretnie na Twoją aplikację). Nadal możesz używać odbiornika zarejestrowanego w kontekście, gdy użytkownik aktywnie korzysta z Twojej aplikacji.
Android 7.0
Android 7.0 (poziom interfejsu API 24) i nowsze wersje nie wysyłają tych transmisji systemowych:
Aplikacje kierowane na Androida 7.0 lub nowszego muszą rejestrować transmisję CONNECTIVITY_ACTION za pomocą funkcji registerReceiver(BroadcastReceiver, IntentFilter). Deklarowanie odbiorcy w manifeście nie działa.
Odbieranie komunikatów
Aplikacje mogą odbierać transmisje na 2 sposoby: za pomocą odbiorników zarejestrowanych w kontekście i odbiorników zadeklarowanych w pliku manifestu.
Odbiorniki zarejestrowane w kontekście
Odbiorniki zarejestrowane w kontekście otrzymują transmisje, dopóki ich kontekst rejestracji jest ważny. Zwykle jest to okres między połączeniami z registerReceiver a unregisterReceiver. Kontekst rejestracji staje się też nieprawidłowy, gdy system niszczy odpowiedni kontekst. Jeśli na przykład zarejestrujesz się w kontekście Activity, będziesz otrzymywać transmisje tak długo, jak długo aktywność pozostanie aktywna. Jeśli zarejestrujesz się w kontekście aplikacji, będziesz otrzymywać transmisje, dopóki aplikacja jest uruchomiona.
Aby zarejestrować odbiornik z kontekstem, wykonaj te czynności:
W pliku kompilacji na poziomie modułu aplikacji dołącz bibliotekę AndroidX Core w wersji 1.9.0 lub nowszej:
Groovy
dependencies { def core_version = "1.19.1" // Java language implementation implementation "androidx.core:core:$core_version" // Kotlin implementation "androidx.core:core-ktx:$core_version" // To use RoleManagerCompat implementation "androidx.core:core-role:1.1.0" // To use the Animator APIs implementation "androidx.core:core-animation:1.0.0" // To test the Animator APIs androidTestImplementation "androidx.core:core-animation-testing:1.0.0" // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation "androidx.core:core-performance:1.0.0" // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation "androidx.core:core-google-shortcuts:1.1.0" // Optional - to support backwards compatibility of RemoteViews implementation "androidx.core:core-remoteviews:1.1.0" // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation "androidx.core:core-splashscreen:1.2.0" }
Kotlin
dependencies { val core_version = "1.19.1" // Java language implementation implementation("androidx.core:core:$core_version") // Kotlin implementation("androidx.core:core-ktx:$core_version") // To use RoleManagerCompat implementation("androidx.core:core-role:1.1.0") // To use the Animator APIs implementation("androidx.core:core-animation:1.0.0") // To test the Animator APIs androidTestImplementation("androidx.core:core-animation-testing:1.0.0") // Optional - To enable APIs that query the performance characteristics of GMS devices. implementation("androidx.core:core-performance:1.0.0") // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google implementation("androidx.core:core-google-shortcuts:1.1.0") // Optional - to support backwards compatibility of RemoteViews implementation("androidx.core:core-remoteviews:1.1.0") // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 implementation("androidx.core:core-splashscreen:1.2.0") }
Utwórz instancję
BroadcastReceiver:Kotlin
val myBroadcastReceiver = MyBroadcastReceiver()Java
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();Utwórz instancję
IntentFilter:Kotlin
val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")Java
IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");Wybierz, czy odbiornik transmisji ma być eksportowany i widoczny dla innych aplikacji na urządzeniu. Jeśli ten odbiornik nasłuchuje transmisji wysyłanych przez system lub inne aplikacje (nawet te, które należą do Ciebie), użyj flagi
RECEIVER_EXPORTED. Jeśli odbiornik nasłuchuje tylko transmisji wysyłanych przez Twoją aplikację, użyj flagiRECEIVER_NOT_EXPORTED.Kotlin
val listenToBroadcastsFromOtherApps = false val receiverFlags = if (listenToBroadcastsFromOtherApps) { ContextCompat.RECEIVER_EXPORTED } else { ContextCompat.RECEIVER_NOT_EXPORTED }Java
boolean listenToBroadcastsFromOtherApps = false; int receiverFlags = listenToBroadcastsFromOtherApps ? ContextCompat.RECEIVER_EXPORTED : ContextCompat.RECEIVER_NOT_EXPORTED;Zarejestruj odbiornik, dzwoniąc pod numer
registerReceiver():Kotlin
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)Java
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);Aby przestać otrzymywać transmisje, zadzwoń pod numer
unregisterReceiver(android.content.BroadcastReceiver). Pamiętaj, aby wyrejestrować odbiornik, gdy nie będzie już potrzebny lub gdy kontekst przestanie być ważny.
Wyrejestrowywanie odbiornika
Gdy odbiornik transmisji jest zarejestrowany, przechowuje odwołanie do obiektu Context, w którym został zarejestrowany. Może to potencjalnie powodować wycieki, jeśli zarejestrowany zakres odbiorcy przekracza zakres cyklu życia kontekstu. Może to nastąpić na przykład wtedy, gdy zarejestrujesz odbiornik w zakresie aktywności, ale zapomnisz go wyrejestrować, gdy system zniszczy aktywność. Dlatego zawsze wyrejestrowuj odbiornik transmisji.
Kotlin
class MyActivity : ComponentActivity() {
private val myBroadcastReceiver = MyBroadcastReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
setContent { MyApp() }
}
override fun onDestroy() {
super.onDestroy()
// When you forget to unregister your receiver here, you're causing a leak!
this.unregisterReceiver(myBroadcastReceiver)
}
}
Java
class MyActivity extends ComponentActivity {
MyBroadcastReceiver myBroadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
// Set content
}
}
Rejestrowanie odbiorników w najmniejszym zakresie
Odbiornik transmisji powinien być rejestrowany tylko wtedy, gdy jesteś zainteresowany wynikiem. Wybierz najmniejszy możliwy zakres odbiorcy:
LifecycleResumeEffectlub metody cyklu życia aktywnościonResume/onPause: odbiornik transmisji otrzymuje aktualizacje tylko wtedy, gdy aplikacja jest w stanie wznowienia.LifecycleStartEffectlub metody cyklu życia aktywnościonStart/onStop: odbiornik transmisji otrzymuje aktualizacje tylko wtedy, gdy aplikacja jest w stanie wznowienia.DisposableEffect: odbiornik transmisji otrzymuje aktualizacje tylko wtedy, gdy funkcja kompozycyjna znajduje się w drzewie kompozycji. Ten zakres nie jest powiązany z zakresem cyklu życia działania. Zarejestruj odbiornik w kontekście aplikacji. Dzieje się tak, ponieważ funkcja kompozycyjna może teoretycznie przetrwać zakres cyklu życia aktywności i spowodować wyciek aktywności.- Aktywność
onCreate/onDestroy: odbiornik transmisji otrzymuje aktualizacje, gdy aktywność jest w stanie utworzenia. Pamiętaj, aby wyrejestrować się wonDestroy(), a nie wonSaveInstanceState(Bundle), ponieważ może to nie zostać wywołane. - Zakres niestandardowy: możesz na przykład zarejestrować odbiornik w zakresie
ViewModel, aby przetrwał ponowne utworzenie aktywności. Do rejestrowania odbiornika używaj kontekstu aplikacji, ponieważ odbiornik może przetrwać zakres cyklu życia aktywności i spowodować wyciek aktywności.
Tworzenie funkcji kompozycyjnych stanowych i bezstanowych
Compose zawiera funkcje kompozycyjne stanowe i bezstanowe. Rejestrowanie lub wyrejestrowywanie odbiornika transmisji w funkcji kompozycyjnej sprawia, że jest ona stanowa. Funkcja kompozycyjna nie jest funkcją deterministyczną, która renderuje tę samą treść po przekazaniu tych samych parametrów. Stan wewnętrzny może się zmieniać w zależności od wywołań zarejestrowanego odbiornika transmisji.
Zgodnie ze sprawdzonymi metodami w Compose zalecamy dzielenie funkcji kompozycyjnych na wersje ze stanem i bez stanu. Dlatego zalecamy przeniesienie tworzenia odbiornika transmisji poza funkcję kompozycyjną, aby była ona bezstanowa:
@Composable
fun MyStatefulScreen() {
val myBroadcastReceiver = remember { MyBroadcastReceiver() }
val context = LocalContext.current
LifecycleStartEffect(true) {
// ...
ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
}
MyStatelessScreen()
}
@Composable
fun MyStatelessScreen() {
// Implement your screen
}
Odbiorniki zadeklarowane w pliku manifestu
Jeśli zadeklarujesz odbiornik transmisji w manifeście, system uruchomi aplikację po wysłaniu transmisji. Jeśli aplikacja nie jest jeszcze uruchomiona, system ją uruchomi.
Aby zadeklarować odbiornik transmisji w pliku manifestu, wykonaj te czynności:
Określ element
<receiver>w pliku manifestu aplikacji.<!-- If this receiver listens for broadcasts sent from the system or from other apps, even other apps that you own, set android:exported to "true". --> <receiver android:name=".MyBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="com.example.snippets.ACTION_UPDATE_DATA" /> </intent-filter> </receiver>Filtry intencji określają działania związane z emisją, do których subskrybuje odbiornik.
Utwórz podklasę
BroadcastReceiveri zastosuj interfejsonReceive(Context, Intent). Odbiornik transmisji w poniższym przykładzie rejestruje i wyświetla zawartość transmisji:Kotlin
class MyBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var dataRepository: DataRepository override fun onReceive(context: Context, intent: Intent) { if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") { val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data" // Do something with the data, for example send it to a data repository: dataRepository.updateData(data) } } }Java
public static class MyBroadcastReceiver extends BroadcastReceiver { @Inject DataRepository dataRepository; @Override public void onReceive(Context context, Intent intent) { if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) { String data = intent.getStringExtra("com.example.snippets.DATA"); // Do something with the data, for example send it to a data repository: if (data != null) { dataRepository.updateData(data); } } } }
Menedżer pakietów systemowych rejestruje odbiornik po zainstalowaniu aplikacji. Odbiornik staje się wtedy osobnym punktem wejścia do aplikacji, co oznacza, że system może uruchomić aplikację i dostarczyć transmisję, nawet jeśli aplikacja nie jest uruchomiona.
System tworzy nowy obiekt komponentu BroadcastReceiver, który obsługuje każdą otrzymaną transmisję. Ten obiekt jest ważny tylko przez czas trwania połączenia z usługą onReceive(Context, Intent). Gdy kod zostanie zwrócony z tej metody, system uzna, że komponent nie jest już aktywny.
Wpływ na stan procesu
To, czy BroadcastReceiver działa, czy nie, wpływa na zawarty w nim proces, co może zmienić prawdopodobieństwo wyłączenia systemu. Proces na pierwszym planie wykonuje metodę onReceive() odbiornika. System uruchamia proces, z wyjątkiem sytuacji, gdy występuje ekstremalne obciążenie pamięci.
System wyłącza BroadcastReceiver po onReceive().
Znaczenie procesu hosta odbiorcy zależy od komponentów aplikacji. Jeśli ten proces obsługuje tylko odbiornik zadeklarowany w pliku manifestu, system może go zakończyć po onReceive(), aby zwolnić zasoby dla innych, ważniejszych procesów. Jest to typowe w przypadku aplikacji, z którymi użytkownik nigdy nie wchodził w interakcję lub nie robił tego ostatnio.
Dlatego odbiorniki transmisji nie powinny inicjować długotrwałych wątków w tle.
System może w dowolnym momencie po onReceive() przerwać proces, aby odzyskać pamięć, i zakończyć utworzony wątek. Aby utrzymać proces, zaplanuj JobService z odbiornika za pomocą JobScheduler, aby system wiedział, że proces nadal działa. Więcej informacji znajdziesz w artykule Omówienie pracy w tle.
Wysyłanie komunikatów
Android udostępnia 2 sposoby wysyłania transmisji przez aplikacje:
- Metoda
sendOrderedBroadcast(Intent, String)wysyła transmisje do jednego odbiorcy naraz. Gdy każdy odbiorca wykonuje działanie po kolei, może przekazać wynik do następnego odbiorcy. Może też całkowicie przerwać transmisję, aby nie docierała do innych odbiorników. Możesz kontrolować kolejność, w jakiej odbiorniki są uruchamiane w ramach tego samego procesu aplikacji. Aby to zrobić, użyj atrybutuandroid:prioritypasującego filtra intencji. Odbiorniki o tym samym priorytecie są uruchamiane w dowolnej kolejności. - Metoda
sendBroadcast(Intent)wysyła transmisje do wszystkich odbiorców w nieokreślonej kolejności. Jest to tzw. transmisja normalna. Jest to bardziej wydajne, ale oznacza, że odbiorcy nie mogą odczytywać wyników innych odbiorców, propagować danych otrzymanych z transmisji ani przerywać transmisji.
Poniższy fragment kodu pokazuje, jak wysłać transmisję przez utworzenie intencji i wywołanie sendBroadcast(Intent).
Kotlin
val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
putExtra("com.example.snippets.DATA", newData)
setPackage("com.example.snippets")
}
context.sendBroadcast(intent)
Java
Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);
Komunikat jest opakowany w obiekt Intent. Ciąg znaków action intencji musi zawierać składnię nazwy pakietu Java aplikacji i jednoznacznie identyfikować transmitowane wydarzenie. Do intencji możesz dołączyć dodatkowe informacje za pomocą parametru putExtra(String, Bundle). Możesz też ograniczyć transmisję do zestawu aplikacji w tej samej organizacji, wywołując metodę setPackage(String) w intencji.
Ograniczanie transmisji za pomocą uprawnień
Uprawnienia umożliwiają ograniczenie transmisji do zestawu aplikacji, które mają określone uprawnienia. Możesz wymusić ograniczenia dotyczące nadawcy lub odbiorcy transmisji.
Wysyłanie transmisji z uprawnieniami
Gdy wywołasz funkcję sendBroadcast(Intent, String) lub sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
Bundle), możesz określić parametr uprawnień. Tylko odbiorniki, które poprosiły o to uprawnienie za pomocą tagu <uses-permission> w pliku manifestu, mogą odbierać transmisję. Jeśli uprawnienie jest niebezpieczne, musisz je przyznać, zanim odbiorca będzie mógł odebrać transmisję. Na przykład ten kod wysyła transmisję z uprawnieniami:
Kotlin
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)
Java
context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);
Aby otrzymać transmisję, aplikacja odbierająca musi poprosić o uprawnienia w ten sposób:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Możesz określić istniejące uprawnienie systemowe, np. BLUETOOTH_CONNECT, lub zdefiniować uprawnienie niestandardowe za pomocą elementu <permission>. Informacje o uprawnieniach i bezpieczeństwie w System Permissions.
Odbieranie transmisji z uprawnieniami
Jeśli podczas rejestrowania odbiornika transmisji określisz parametr uprawnień (za pomocą tagu registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) lub <receiver> w pliku manifestu), tylko nadawcy, którzy poprosili o uprawnienia za pomocą tagu <uses-permission> w pliku manifestu, mogą wysyłać do odbiornika intencję. Jeśli uprawnienie jest niebezpieczne, nadawca musi również otrzymać to uprawnienie.
Załóżmy na przykład, że aplikacja odbierająca ma odbiornik zadeklarowany w manifeście w ten sposób:
<!-- If this receiver listens for broadcasts sent from the system or from
other apps, even other apps that you own, set android:exported to "true". -->
<receiver
android:name=".MyBroadcastReceiverWithPermission"
android:permission="android.permission.ACCESS_COARSE_LOCATION"
android:exported="true">
<intent-filter>
<action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
</intent-filter>
</receiver>
lub aplikacja odbierająca ma odbiornik zarejestrowany w kontekście w ten sposób:
Kotlin
ContextCompat.registerReceiver(
context, myBroadcastReceiver, filter,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
null, // scheduler that defines thread, null means run on main thread
receiverFlags
)
Java
ContextCompat.registerReceiver(
context, myBroadcastReceiver, filter,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
null, // scheduler that defines thread, null means run on main thread
receiverFlags
);
Aby móc wysyłać transmisje do tych odbiorników, aplikacja wysyłająca musi poprosić o zezwolenie w ten sposób:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Unikaj transmisji w ramach tego samego procesu
Transmisje są mechanizmem komunikacji międzyprocesowej (IPC) służącym do wysyłania wiadomości między różnymi aplikacjami lub między systemem a aplikacjami. Wysyłanie komunikatu do samego siebie, czyli komunikatu, w przypadku którego wszyscy odbiorcy działają w tym samym procesie, który wysłał komunikat, jest bardzo nieefektywne, powoduje niepotrzebne obciążenie systemu i jest zdecydowanie odradzane.
2 typowe scenariusze, w których aplikacje wysyłają do siebie transmisje:
Komunikacja między komponentami w tym samym procesie: na przykład przekazywanie zdarzeń lub danych między aktywnościami, fragmentami, usługami lub wątkami w tle. Zamiast wysyłać transmisje, używaj standardowych mechanizmów komunikacji w procesie, takich jak wzorzec obserwatora lub strumienie reaktywne:
- Kotlin Flows (
SharedFlowiStateFlow): nowoczesne, idiomatyczne rozwiązanie w Kotlinie do emitowania i obserwowania strumieni zdarzeń lub aktualizacji stanu w różnych współprogramach i komponentach aplikacji. - Udostępniony
ViewModel: ułatwia udostępnianie danych i zdarzeń między różnymi komponentami interfejsu (np. fragmentami lub komponentami kompozycyjnymi) w ramach tej samej aktywności. - Wywołania zwrotne i odbiorniki: standardowe wywołania zwrotne interfejsu lub odwołania do funkcji przekazywane bezpośrednio między komponentami albo rejestrowane w centralnym repozytorium lub kontrolerze.
- Kotlin Flows (
Obsługa zdarzeń systemowych, zadań lub alarmów: na przykład odbieranie zaplanowanego zadania, alarmu lub wywołania zwrotnego systemu, a następnie wysyłanie transmisji w celu wywołania rzeczywistej pracy. Zamiast wysyłać transmisję, wykonaj pracę bezpośrednio w ramach tego zadania (np. w przypadku
JobServicelub komponentu roboczego WorkManager), procedury obsługi alarmu lub komponentu wywołania zwrotnego systemu albo przekaż zadanie bezpośrednio do klas logiki biznesowej aplikacji.
Na urządzeniach z Androidem 17 QPR2 lub nowszym system wydajniej dostarcza transmisje własne, zwracając je do procesu wysyłania, który dostarcza je do własnych odbiorników w głównym wątku. Wysłanie transmisji do siebie nie zwiększa ważności procesu i nie zapobiega zamrożeniu procesu w pamięci podręcznej, więc nie polegaj na transmisjach do siebie, aby utrzymać działanie aplikacji lub wykonywać pracę w tle. Nawet po tej optymalizacji samodzielne transmisje są mniej wydajne niż mechanizmy komunikacji w trakcie procesu, więc zamiast nich używaj tych alternatyw.
Więcej informacji o projektowaniu komunikacji między komponentami aplikacji znajdziesz w przewodniku po architekturze aplikacji.
Bezpieczeństwo
Oto kilka kwestii związanych z bezpieczeństwem wysyłania i odbierania transmisji:
Jeśli wiele aplikacji zarejestruje się w pliku manifestu, aby otrzymywać tę samą transmisję, system może uruchomić wiele aplikacji, co będzie miało znaczący wpływ na wydajność urządzenia i komfort użytkownika. Aby tego uniknąć, zamiast deklaracji w pliku manifestu używaj rejestracji kontekstu. Czasami system Android sam wymusza używanie odbiorników zarejestrowanych w kontekście. Na przykład transmisja
CONNECTIVITY_ACTIONjest dostarczana tylko do odbiorników zarejestrowanych w kontekście.Nie przesyłaj informacji poufnych za pomocą intencji ogólnej. Każda aplikacja może odczytać te informacje, jeśli zarejestruje się w celu otrzymywania transmisji. Istnieją 3 sposoby kontrolowania, kto może otrzymywać Twoje transmisje:
- Podczas wysyłania transmisji możesz określić uprawnienia.
- W Androidzie 4.0 (poziom interfejsu API 14) i nowszym możesz określić pakiet z
setPackage(String)podczas wysyłania transmisji. System ogranicza transmisję do zestawu aplikacji, które pasują do pakietu.
Gdy zarejestrujesz odbiornik, każda aplikacja może wysyłać do niego potencjalnie szkodliwe transmisje. Istnieje kilka sposobów ograniczania liczby transmisji, które otrzymuje Twoja aplikacja:
- Podczas rejestrowania odbiornika transmisji możesz określić uprawnienia.
- W przypadku odbiorców zadeklarowanych w pliku manifestu możesz ustawić w nim atrybut android:exported na wartość „false”. Odbiornik nie otrzymuje transmisji ze źródeł spoza aplikacji.
Przestrzeń nazw działań związanych z transmisją jest globalna. Upewnij się, że nazwy działań i inne ciągi znaków są zapisane w przestrzeni nazw, której jesteś właścicielem. W przeciwnym razie możesz nieumyślnie spowodować konflikt z innymi aplikacjami.
Ponieważ metoda odbiorcy
onReceive(Context, Intent)jest uruchamiana w głównym wątku, powinna być wykonywana i zwracać wartość szybko. Jeśli musisz wykonać długotrwałą pracę, uważaj na tworzenie wątków lub uruchamianie usług w tle, ponieważ system może zakończyć cały proces po powrocie z funkcjionReceive(). Więcej informacji znajdziesz w sekcji Wpływ na stan procesu. Aby wykonać długotrwałe zadanie, zalecamy:- Wywołanie metody
goAsync()w metodzieonReceive()odbiornika i przekazanieBroadcastReceiver.PendingResultdo wątku w tle. Dzięki temu transmisja pozostanie aktywna po powrocie zonReceive(). Jednak nawet w tym przypadku system oczekuje, że zakończysz transmisję bardzo szybko (w ciągu 10 sekund). Umożliwia przeniesienie pracy do innego wątku, aby uniknąć zakłóceń w wątku głównym. - Planowanie zadania za pomocą narzędzia
JobScheduler. Więcej informacji znajdziesz w artykule Inteligentne planowanie zadań.
- Wywołanie metody
Nie rozpoczynaj działań z odbiorników transmisji, ponieważ może to negatywnie wpłynąć na komfort użytkownika, zwłaszcza jeśli jest więcej niż jeden odbiornik. Zamiast tego możesz wyświetlić powiadomienie.