Kiedy rejestrować / wyrejestrowywać odbiorców transmisji utworzonych w działaniu?

79

Muszę utworzyć niestandardowy odbiornik transmisji w zdarzeniu onCreate działania i oczywiście muszę wyrejestrować odbiornik transmisji w zdarzeniu onDestroy działania

Dla jasności jest to fragment kodu, którego używam

public class AnActivity extends Activity {
    private ResponseReceiver receiver;

    public class ResponseReceiver extends BroadcastReceiver {
           public static final String ACTION_RESP =
              "mypackagename.intent.action.MESSAGE_PROCESSED";

           @Override
            public void onReceive(Context context, Intent intent) {
// TODO Start a dialogue if message indicates successfully posted to server
            }
    }   

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
        filter.addCategory(Intent.CATEGORY_DEFAULT);
        receiver = new ResponseReceiver();
        registerReceiver(receiver, filter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }

Przeczytałem, że zdarzenia onPause / onResume i onStart / onStop dla tej czynności powinny również rejestrować i wyrejestrowywać odbiornik transmisji.

Naprawdę chcę zrozumieć, co jest uważane za najlepszą praktykę w tym zakresie i dlaczego.

jamesc
źródło
Dzieje się tak, ponieważ gdy onDestroy()zostanie wywołany, zdarzenia nie będą już nasłuchiwać przez odbiornik.
de_billa_

Odpowiedzi:

91

Należy zarejestrować i wyrejestrować swoich odbiorców onStart()i onStop().

Jedynym powodem, dla którego Działanie mogłoby zarejestrować BroadcastReceivers, jest wykorzystanie wydarzeń w jakiś sposób w bieżącej aktywności, aby poinformować Użytkownika o zdarzeniu. Jeśli onStop()został wywołany, Activityto nie jest już na pierwszym planie i dlatego nie może zaktualizować użytkownika.

Jeśli chcesz odbierać wydarzenia w tle, powinieneś rozważyć skorzystanie z usługi wskazanej tutaj .

Jak mówi Konstantin, onDestroy()nie ma gwarancji, że zostaniesz wezwany, i możesz kontynuować odbieranie programów przez długi czas, gdy Activitynie będzie już otwarty.

SnowyTracks
źródło
3
Sugerujesz, żebym zarejestrował się w onResume ZAMIAST onCreate, czy też? Czy onResume jest zawsze wywoływany podczas tworzenia działania?
jamesc,
9
Powinieneś zarejestrować się onResume tak, onResume () jest zawsze wywoływana przy wyświetlanej aktywności (jest to ostatnia metoda wywołana przed pojawieniem się aktywności ( developer.android.com/reference/android/app/Activity.html ), jeśli zarejestrujesz się tylko w onCreate () i wyrejestruj onPause (), to następnym razem, gdy aktywność zostanie przeniesiona na pierwszy plan, onCreate () nie zostanie ponownie wywołana i wtedy nie zarejestruje ponownie odbiorcy. I tak mam na myśli ZAMIAST, nie rób tego onCreate ().
SnowyTracks,
1
@SnowyTracks: czy możesz skomentować, dlaczego lepiej jest wykonywać wywołania rejestracyjne BroadcastReceiver w onResume / onPause niż onStart / onStop? Przeglądając przewodnik dla programistów dotyczący powiązanych usług, znalazłem to . Pod koniec tej sekcji zaleca się wykonanie wiązania / usuwania wiązania usługi w onStart / onStop zamiast onResume / onPause (ze względu na wydajność). Zastanawiam się, czy dotyczy to również BroadcastReceivers? Z góry dziękuję.
Janus Varmarken
1
@jvmk Zgoda, dokument na Androida mówi, że należy to robić w onStart i onStop, myślę, że w 99% przypadków nie ma to większego znaczenia, różnica w zachowaniu jest tylko w przypadku działań dialogowych lub częściowych działań na pierwszym planie. Ale zaktualizuję moją odpowiedź, aby była zgodna z dokumentem Androida
SnowyTracks
1
Widzę, że wczoraj zredagowałeś drugi akapit ... dzięki za wysiłek w uzyskaniu bardziej spójnej odpowiedzi. Ale nadal nie wyjaśnia, dlaczego należy używać onStart / onStop zamiast lub w połączeniu z onResume / onPause , co było pytaniem OP. Zamiast tego, wyjaśnienie z drugiego akapitu jest tak samo prawdziwe dla onResume / onPause, jak i onStart / onStop: po wywołaniu onPause czynność nie jest już na pierwszym planie. Więc pozostajemy bez "dlaczego" dla twojej rekomendacji.
LarsH
19

Ponieważ onDestroy()nie gwarantuje się, że zostaniesz wezwany, skorzystaj onPause()z opcji wyrejestrowania. Weź pod uwagę cykl życia swojego odbiornika telewizyjnego: czy potrzebujesz go, aby był aktywny tylko wtedy, gdy Twoja aktywność jest na pierwszym planie? Następnie użyj onResume()/onPause()

Konstantin Pribluda
źródło
co, jeśli nadal musimy aktualizować zawartość w aktywności, nawet jeśli aktywność jest w tle, ponieważ użytkownik może wznowić aplikację i w takim przypadku powinny zostać wyświetlone zaktualizowane dane?
Usman Rana
9

Dokumentacja Androida nie określa jednego miejsca do zarejestrowania / wyrejestrowania odbiorników transmisji, ale wspomina zarówno onStart()/ onStop()i onResume()/ onPause()jako możliwości.

Najważniejszym czynnikiem przy podejmowaniu tej decyzji jest to, kiedy odbiorca musi być w stanie wykonywać swoją pracę? To określi, kiedy się zarejestrować i wyrejestrować.

  • Czy odbiorca musi coś zrobić z transmisją tylko wtedy, gdy aktywność jest w centrum uwagi? Jeśli tak, możesz zarejestrować / wyrejestrować go w onPause()/ onReceive(). (Możesz również użyć dłuższej żywotności, na przykład onStart()/ onStop(), ale wtedy powinieneś sprawdzić podczas odbiornika, onReceive()czy aktywność jest w centrum uwagi.)

  • Czy odbiorca musi coś zrobić, gdy jest widoczny, nawet jeśli nie ma na nim fokusu (np. Podczas pokazywania okna dialogowego)? Jeśli tak, użyj onStart()/ onStop()(lub dłuższej żywotności, ale znowu odbiornik onReceive()powinien sprawdzić, czy aktywność jest widoczna).

  • Czy odbiorca musi wiedzieć o transmisji, nawet jeśli aktywność nie jest widoczna? Na przykład, czy musi pamiętać, że coś się wydarzyło, aby gdy aktywność stała się widoczna, mogła odzwierciedlać wynikający z niej stan rzeczy? Następnie musisz użyć onCreate()/, onDestroy()aby zarejestrować / wyrejestrować. (Zauważ, że istnieją inne sposoby implementacji tego rodzaju funkcji).

Jeśli się zarejestrujesz onStart(), nie rejestruj ich również onResume(), ponieważ byłoby to zbędne: onResume()nigdy nie jest wywoływane bez wcześniejszego onStart()wywołania.

Pamiętaj też, że najlepiej jest pozostawać włączoną pauzę () tak lekką, jak to tylko możliwe :

Wykonanie onPause () jest bardzo krótkie i niekoniecznie zapewnia wystarczająco dużo czasu na wykonanie operacji składowania. Z tego powodu nie należy używać onPause () do zapisywania aplikacji lub danych użytkownika, wykonywania wywołań sieciowych lub wykonywania transakcji w bazie danych; taka praca może nie zostać zakończona przed zakończeniem metody. Zamiast tego podczas onStop () należy wykonywać operacje zamykania systemu przy dużym obciążeniu.

To prawda, że wywołanie nieonDestroy() jest gwarantowane, jeśli system zabije proces w celu zaoszczędzenia pamięci. Jeśli jednak proces zostanie zabity, proces i tak nie będzie odbierał transmisji. W takim razie czy naprawdę konieczne jest wyrejestrowanie odbiorników transmisji?

LarsH
źródło
Dziękuję za odpowiedź na moje pytanie, ale twoja odpowiedź jest zagmatwana i nie do końca ścisła. Mówisz, że If you register in onStart(), don't also register them in onPause(), because that would be redundant: onPause() is never called without onStart() being called first.jest po prostu nielogiczna i myląca, zwłaszcza gdy przyjęta odpowiedź jest całkowicie dokładna.
jamesc
@jamesc: Ups, miałem na myśli raczej onResume niż onPause. Masz rację, to trochę zagmatwane. Naprawiono teraz. Jeśli chodzi o zaakceptowaną odpowiedź, skomentowałem ją. Uważam, że ta odpowiedź zawiera istotne i istotne informacje, których zaakceptowany nie oferuje.
LarsH
5

Android może zabić twoją aplikację z pominięciem onStop()metody. Najlepszym sposobem rozwiązania tej sytuacji jest zarejestrowanie się BroadcastReceiverw onResume()metodzie i wyrejestrowanie się onPause().

ukson
źródło
1
Ja też to robię. Miałem problemy z onStop()aswell
Vygintas B
0

Powinieneś zarejestrować i wyrejestrować swoją transmisję za pomocą metod onResume () i onPause ().

jeśli zarejestrujesz się w onStart () i wyrejestrujesz go w onStop (). tym razem otrzymasz następujący numer.

jeśli ekran Twojego urządzenia jest zablokowany w momencie wywołania onStop (), a jeśli odblokujesz ten czas, onStart () nigdy nie zostanie wywołany. dlatego musisz zarejestrować i wyrejestrować go w metodach onResume () i onPause ().

Mayuresh Deshmukh
źródło