2013-03-14 2 views
5

Jestem obecnie rozwijających Android aplikacji, która ma następujące wymagania:Co jest preferowanym sposobem wywołania Android Aktywny powrotem z wątku Służby

Wątek pracownik rozpoczął w Serwisie. Wątek ten jest przetwarzany i należy go wywołać z głównej aktywności i dostarczyć asynchroniczne odpowiedzi na to samo działanie.

Wywoływanie usługi z działalności jest łatwe (IBinder rzeczy)

Moje pytanie jest teraz o prawidłowej realizacji usług zwrotnego.

Najpierw dodałem obiekt android.os.Handler do działania i obsłużyłem go w MyActivity.handleMessage (Message), ale wymaga to podania odniesienia do tej usługi. Co się dzieje, gdy system operacyjny Android postanowi zniszczyć/ponownie utworzyć moją aktywność z powodu zmiany orientacji na przykład? Czy moja aktywność pozostaje żywa, ponieważ jest przywoływana (pośrednio) w serwisie? Jeśli mimo to działanie zostanie zniszczone/odbudowane, co stanie się z moim odwołaniem do obsługi w serwisie?

Chyba nie używam właściwą metodę callback działalność z wątku usług, więc chciałem się dowiedzieć, czy ktoś może wskazać mi właściwą drogę robi.

TIA

+0

Wiem, że mogłem dodać/usunąć Handler działania z usługi onPause/onResume, ale chciałem się dowiedzieć, czy istnieje lepszy interfejs API, który przeoczyłem – alberthier

Odpowiedz

4

Wolę używając LocalBroadcastManager

Oto przykład kodu w swojej Activity:

BroadcastReceiver localBroadcastReceiver = new BroadcastReceiver() 
{ 
    @Override 
    public void onReceive(Context context, Intent intent) 
    { 
     Log.d("BroadcastReceiver", "Message received " + intent.getAction()); 
     Log.d("BroadcaseReceiver", "Received data " + intent.getStringExtra("com.my.package.intent.EXTRA_DATA")); 
    } 
}; 

@Override 
protected void onStart() 
{ 
    super.onStart(); 
    final LocalBroadcastManager localBroadcastManager = 
     LocalBroadcastManager.getInstance(this); 
    final IntentFilter localFilter = new IntentFilter(); 
    localFilter.addAction("com.my.package.intent.ACTION_NAME_HERE"); 
    localBroadcastManager.registerReceiver(localBroadcastReceiver, localFilter); 
} 

@Override 
protected void onStop() 
{ 
    super.onStop(); 
    final LocalBroadcastManager localBroadcastManager = 
     LocalBroadcastManager.getInstance(this); 
    // Make sure to unregister!! 
    localBroadcastManager.unregisterReceiver(localBroadcastReceiver); 
} 

nigdzie indziej w swoim kodzie (taki jak w zakończeniu swojej wątku tła):

final LocalBroadcastManager localBroadcastManager = 
    LocalBroadcastManager.getInstance(context); 
final Intent intent = new Intent("com.my.package.intent.ACTION_NAME_HERE") 
intent.putExtra("com.my.package.intent.EXTRA_DATA", yourBackgroundData); 
localBroadcastManager.sendBroadcast(intent); 

Możesz oczywiście użyć intent.putExtra, aby dodać dodatkowe dane lub użyć wielu akcji, aby rozróżnić transmisję wiadomości.

0

Jednym z rozwiązań, jak mówisz, jest użycie MyActivity.handleMessage (Message). Za każdym razem, gdy twoja aktywność się rozpocznie (lub zostanie wznowiona) prawdopodobnie podejmiesz próbę uruchomienia usługi (wspomniane rzeczy "onBind"). Jeśli usługa jest już uruchomiona, nie szkodzi. Po zakończeniu bindowania powiadamia się usługę, z której Messenger wysyła odpowiedzi.

Aby zapewnić ponowne uruchomienie, w usłudze onStop musisz poinformować serwis, aby usunął tego Messengera z "listy miejsc do wysłania odpowiedzi", tak aby nie przypadkowo wysłać wiadomość do nieistniejącego Komunikatora . Kiedy onStart zostanie wywołany jako część restartu, wyśle ​​teraz poprawnego Messengera.

Oczywiście wymaga to usługa z tym poradzić i jakoś zarządzać scenariusz, w którym ma odpowiedzi do wysyłania natomiast nie ma Messenger wysłać go. Dotyczy to informacji do momentu, w którym Messenger jest dostępny lub upuszcza informacje, a Activity pobiera wszystkie informacje o stanie jawnie jako kontynuację powiązań, które wykonał w onStart.

Innym podejściem jest, aby ankieta dotycząca aktywności w serwisie była przeprowadzana tak często (10 sekund?), Gdy wie, że trwa przetwarzanie, aby sprawdzić, czy wyniki są dostępne, a następnie, aby zatrzymać odpytywanie po odzyskaniu wszystkich informacji. .

0

Dla asynchronicznych wywołań usług, należałoby przekazać odniesienie zwrotną momencie zainicjowania go, powiedziałbym.

Funkcja zwrotna ma być wykonana przez nitkę spoiwa, który jest standardem dla tego podejścia.

Oczywiście, aktywność, która inicjuje wezwanie może polegać na tym, że gwint spoiwo działa w swoim procesie. Łatwo więc wrócić do wątku głównego/interfejsu użytkownika z wywołania zwrotnego.

Stąd, jeżeli zwrotna musi przetworzyć coś w głównym wątku/UI, to po prostu wykorzystuje

(new Handler(Looper.getMainLooper()).post() 

który ma tę zaletę, że znajdzie się główny wątek/UI dynamicznie w momencie, gdy kod jest wykonywany.Z drugiej strony nie jest to konieczne, ponieważ wątek główny/UI się nie zmienia, więc znalezienie go za pomocą odwołania do widoku lub cokolwiek innego, co możesz mieć pod ręką w wywołaniu zwrotnym również będzie działało.

3

Dokonaliśmy tego, centralizując całą komunikację pomiędzy działaniami i usługami w klasie Application. Rozszerzamy klasę Application i stosujemy tam metody, które wiążą się z usługą i akceptują wywołania zwrotne. Nie ma bezpośredniego połączenia między Activity i Service w tej architekturze.

Zaletą tego mechanizmu jest to, że nie musisz się martwić o rozłączanie/ponowne wiązanie z usługą podczas przejść aktywności i śmierci oraz odtwarzania aktywności. Klasa Application zarządza tym wszystkim i nie wpływa na to, jakie czynności wykonuje. Klasa Application odbiera wszystkie wywołania zwrotne i musisz mieć tam kod, aby określić, co zrobić z tymi oddzwanianiami. Prawdopodobnie będziesz chciał przechowywać pewne dane w klasie Application, a następnie powiadomić działania, że ​​są dostępne nowe dane lub coś podobnego.

Innym podejściem jest, aby Service nadawać wywołania zwrotne. W takim przypadku sprzężenie między usługą i działaniami jest luźne, więc nie trzeba tworzyć w działaniu aktywności Handler, a następnie przekazać ją do Service. Aktywności mogą po prostu zarejestrować BroadcastReceiver s dla wywołań zwrotnych, którymi są zainteresowani, lub możesz zarządzać tym w manifeście.

+0

Dlaczego po prostu nie użyć bezpośrednio aplikacji "Usługa" powiązanej z aplikacją? W tym przypadku będzie on działać tak długo, jak "Aplikacja" i nie będzie potrzeby dodawania żadnej dodatkowej logiki do samej klasy "Aplikacja". –

+0

@DmitryZaitsev Nie jestem pewien, czy rozumiem twój komentarz. To, co opisałem, polega na bezpośrednim powiązaniu usługi z aplikacją. Jednak zazwyczaj logika biznesowa znajduje się w działaniach i decyduje, kiedy powiąż, kiedy się odwiązać, kiedy zażądać czegoś z usługi itp. Klasa "Aplikacja" jest po prostu "pośrednikiem", zarządzającym transportem między działaniami i usługa. –

+0

Ah, przepraszam, źle zrozumiałem twoją odpowiedź. –