Powiąż usługę z aktywnością w systemie Android


90

Próbuję napisać prosty odtwarzacz multimedialny, który odtwarza dźwięk strumieniowy przy użyciu RTSP. Mam działanie GUI i usługę, która wykonuje odtwarzanie. Moje pytanie brzmi jak najlepiej komunikować się pomiędzy działaniem a usługą (np. Aktualizacja GUI na podstawie stanu gracza).

Wiem, że mogę powiązać usługę z działaniem za pomocą onBind (), ale jeśli dobrze zrozumiem, spowoduje to zatrzymanie usługi, jeśli działanie zostanie zabite. Chcę kontynuować odtwarzanie, nawet jeśli użytkownik zakończy działanie. Czy jest jakiś standardowy lub preferowany sposób rozwiązania tego problemu?

Odpowiedzi:


154

„Jeśli uruchomisz usługę systemu Android z startService(..)tą usługą, pozostanie ona uruchomiona do momentu jawnego wywołania stopService(..). Istnieją dwa powody, dla których usługa może być uruchomiona przez system. Jeśli ktoś zadzwoni, Context.startService()system pobierze usługę (utworzy ją i wywoła onCreate()metodę, jeśli potrzebne), a następnie wywołaj swoją onStartCommand(Intent, int, int)metodę z argumentami dostarczonymi przez klienta. Usługa będzie w tym momencie działać do momentu wywołania Context.stopService()lub jej stopSelf()wywołania. Należy pamiętać, że wielokrotne wywołania Context.startService()nie zagnieżdżają się (chociaż skutkują wieloma odpowiadającymi im wywołaniami onStartCommand()), więc nie bez względu na to, ile razy jest uruchamiana, usługa zostanie zatrzymana raz Context.stopService()lub stopSelf()zostanie wywołana; jednak usługi mogą używać ichstopSelf(int) metoda, aby upewnić się, że usługa nie zostanie zatrzymana, dopóki nie zostaną przetworzone rozpoczęte intencje.

Klienci mogą również używać Context.bindService()do uzyskiwania trwałego połączenia z usługą. Powoduje to również utworzenie usługi, jeśli jeszcze nie jest uruchomiona (wywołuje onCreate()podczas wykonywania tej czynności), ale nie wywołuje onStartCommand(). Klient otrzyma IBinderobiekt, który usługa zwraca ze swojej onBind(Intent)metody, umożliwiając klientowi następnie wywołanie z powrotem do usługi. Usługa będzie działać tak długo, jak długo zostanie nawiązane połączenie (niezależnie od tego, czy klient zachowuje odniesienie do Usługi IBinder). Zwykle IBinderzwracany jest dla złożonego interfejsu, który został napisany w AIDL.

Usługę można zarówno uruchomić, jak i powiązać z nią połączenia. W takim przypadku system będzie utrzymywał usługę tak długo, jak długo jest uruchomiona lub istnieje co najmniej jedno połączenie z nią oznaczone Context.BIND_AUTO_CREATEflagą. Gdy żadna z tych sytuacji nie jest spełniona, onDestroy()wywoływana jest metoda Usługi, a usługa zostaje skutecznie zakończona. Całe czyszczenie (zatrzymywanie wątków, wyrejestrowywanie odbiorców) powinno być zakończone po powrocie z onDestroy(). ”


1
trochę zamieszania: czy to prawda, że ​​jeśli działalność zostanie zniszczona, usługa również zostanie zniszczona? A może ta usługa nie zostanie zniszczona tylko wtedy, gdy wdrożę własny AIDL? Pytam, ponieważ kiedy używam startService (szczególnie na IntentService), usługa zatrzymuje się po zakończeniu pracy, a nie po jej zakończeniu. Czy zatem prawdą jest, że jeśli działanie umrze, to służba, która jest związana (wyłącznie) również umiera?
Katedral Pillon

1
jeśli używasz prostego serwera przez wywołanie startService, usługa nie zatrzyma się, dopóki nie wywołasz stopSelf () lub stopService (). A następny, jeśli użyjesz bindService, tak usługa umrze, jeśli wszystkie połączone / bind komponenty zostaną zniszczone.
Asif Mushtaq

1
@UnKnown Jeśli usługa została uruchomiona przy użyciu startService (), to niezależnie od tego, czy ją dowiązujesz, czy rozpinasz, będzie działać dalej i może zostać zniszczona tylko przez wywołanie stopService () lub stopSelf (). Tak więc, nawet jeśli działanie, które było powiązane z usługą, zostanie zniszczone, usługa nie zostanie zniszczona.
CopsOnRoad

Czy możesz mi pomóc z tym pytaniem stackoverflow.com/questions/51508046/…
Rajesh K

25

Przede wszystkim dwie rzeczy, które musimy zrozumieć

Klient

  • wysyła żądanie do określonego serwera

    bindService(new 
        Intent("com.android.vending.billing.InAppBillingService.BIND"),
            mServiceConn, Context.BIND_AUTO_CREATE);`
    

tutaj mServiceConnjest instancja ServiceConnectionklasy (wbudowana), w rzeczywistości jest to interfejs, który musimy zaimplementować z dwoma (pierwszą dla sieci połączonej i drugą niepodłączoną) metodami monitorowania stanu połączenia sieciowego.

serwer

  • Obsługuje żądanie klienta i tworzy własną replikę, która jest prywatna tylko dla klienta, który wysyła żądanie, a ta replika serwera działa w innym wątku.

Teraz po stronie klienta, jak uzyskać dostęp do wszystkich metod serwera?

  • serwer wysyła odpowiedź z IBind Object.so Obiekt IBind jest naszym handlerem, który uzyskuje dostęp do wszystkich metod obsługi za pomocą operatora (.).

    MyService myService;
    public ServiceConnection myConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder binder) {
            Log.d("ServiceConnection","connected");
            myService = binder;
        }
        //binder comes from server to communicate with method's of 
    
        public void onServiceDisconnected(ComponentName className) {
            Log.d("ServiceConnection","disconnected");
            myService = null;
        }
    }
    

teraz jak wywołać metodę, która leży w służbie

myservice.serviceMethod();

oto myServiceprzedmiot i serviceMethodemetoda w służbie. W ten sposób zostaje nawiązana komunikacja między klientem a serwerem.


10

próbowałem zadzwonić

startService(oIntent);
bindService(oIntent, mConnection, Context.BIND_AUTO_CREATE);

w konsekwencji i mogę stworzyć lepką usługę i połączyć się z nią. Szczegółowy samouczek dotyczący przykładu usługi powiązanej .


5

Istnieje metoda o nazwie unbindService, która pobierze ServiceConnection, które utworzysz po wywołaniu bindService. Umożliwi to rozłączenie się z usługą, nie wyłączając jej jednocześnie.

Może to stanowić problem, gdy połączysz się z nim ponownie, ponieważ prawdopodobnie nie wiesz, czy działa, czy nie, gdy ponownie rozpoczynasz działanie, więc musisz wziąć to pod uwagę w swoim kodzie działania.

Powodzenia!


-1

To stronnicza odpowiedź, ale napisałem bibliotekę, która może uprościć korzystanie z usług Androida, jeśli działają lokalnie w tym samym procesie co aplikacja: https://github.com/germnix/acacia

Zasadniczo definiujesz interfejs z adnotacją @Service i jego klasą implementującą, a biblioteka tworzy i wiąże usługę, obsługuje połączenie i wątek roboczy w tle:

@Service(ServiceImpl.class)
public interface MyService {
    void doProcessing(Foo aComplexParam);
}

public class ServiceImpl implements MyService {
    // your implementation
}

MyService service = Acacia.createService(context, MyService.class);
service.doProcessing(foo);

<application
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">
    ...
    <service android:name="com.gmr.acacia.AcaciaService"/>
    ...
</application>

Możesz uzyskać instancję powiązanej usługi android.app.Service, aby ukryć / pokazać trwałe powiadomienia, użyć własnego android.app.Service i ręcznie obsługiwać wątki, jeśli chcesz.


-5

Jeśli użytkownik wycofa się, onDestroy()metoda zostanie wywołana. Ta metoda polega na zatrzymaniu dowolnej usługi używanej w aplikacji. Jeśli więc chcesz kontynuować usługę, nawet jeśli użytkownik wycofa się z aplikacji, po prostu usuń onDestroy(). Mam nadzieję, że to pomoże.


Będziesz musiał nadpisać tę funkcję i usunąć domyślne wywołanie onDestroy () nadklasy, jeśli twoje IDE automatycznie je utworzy. ale dlaczego miałbyś kiedykolwiek chcieć to zrobić?
Riptyde4
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.