Jak usługa Android komunikuje się z Aktywnością

251

Piszę swoją pierwszą aplikację na Androida i staram się skupić na komunikacji między usługami i działaniami. Mam usługę, która będzie działać w tle i rejestrować dane GPS i czasowe. Będę miał działanie, które zostanie wykorzystane do uruchomienia i zatrzymania usługi.

Więc najpierw muszę być w stanie dowiedzieć się, czy usługa jest uruchomiona w momencie uruchomienia działania. Są tutaj inne pytania, więc myślę, że mogę to rozgryźć (ale nie krępuj się udzielić porady).

Mój prawdziwy problem: jeśli działanie jest uruchomione, a usługa jest uruchomiona, potrzebuję sposobu na wysłanie wiadomości do działania. Proste ciągi i liczby całkowite w tym momencie - głównie komunikaty o stanie. Wiadomości nie będą się pojawiać regularnie, więc nie sądzę, aby odpytywanie usługi było dobrym rozwiązaniem, jeśli istnieje inny sposób. Chcę tej komunikacji tylko wtedy, gdy użytkownik uruchomił działanie - nie chcę uruchamiać działania z usługi. Innymi słowy, jeśli uruchomisz działanie i usługa jest uruchomiona, zobaczysz komunikaty o stanie w interfejsie działania, gdy wydarzy się coś interesującego. Jeśli nie rozpoczniesz działania, nie zobaczysz tych wiadomości (nie są one tak interesujące).

Wygląda na to, że powinienem być w stanie ustalić, czy usługa jest uruchomiona, a jeśli tak, dodaj działanie jako detektora. Następnie usuń działanie jako detektora, gdy działanie zostanie wstrzymane lub zatrzymane. Czy to rzeczywiście możliwe? Jedyny sposób, w jaki mogę to zrobić, to mieć implementację działania Parcelable i zbudować plik AIDL, aby móc go przekazać przez zdalny interfejs Usługi. Wydaje się to jednak przesadą i nie mam pojęcia, w jaki sposób działanie powinno implementować writeToParcel () / readFromParcel ().

Czy istnieje łatwiejszy lub lepszy sposób? Dziękuję za wszelką pomoc.

EDYTOWAĆ:

Dla każdego, kto jest zainteresowany tym później, w katalogu przykładów znajduje się przykładowy kod od Google do obsługi tego za pośrednictwem AIDL: /apis/app/RemoteService.java

Scott Saunders
źródło

Odpowiedzi:

94

Istnieją trzy oczywiste sposoby komunikowania się z usługami:

  1. Korzystanie z zamiarów
  2. Korzystanie z AIDL
  3. Korzystanie z samego obiektu usługi (jako singletonu)

W twoim przypadku wybrałbym opcję 3. Zrób statyczne odniesienie do usługi, którą ona sama, i wypełnij ją w onCreate ():

void onCreate(Intent i) {
  sInstance = this;
}

Wykonaj funkcję statyczną MyService getInstance(), która zwraca wartość statycznąsInstance .

Następnie Activity.onCreate()uruchom usługę, asynchronicznie zaczekaj, aż usługa zostanie faktycznie uruchomiona (możesz poprosić swoją usługę o powiadomienie aplikacji, że jest gotowa, wysyłając zamiar do działania.) I uzyskać jej instancję. Gdy masz instancję, zarejestruj obiekt nasłuchiwania usługi w swojej usłudze i gotowe. UWAGA: podczas edytowania widoków wewnątrz działania należy zmodyfikować je w wątku interfejsu użytkownika, usługa prawdopodobnie uruchomi swój własny wątek, więc musisz zadzwonić Activity.runOnUiThread().

Ostatnią rzeczą, którą musisz zrobić, to usunąć odwołanie do twojego obiektu nasłuchującego, w Activity.onPause()przeciwnym razie wystąpi wyciek kontekstu działania.

UWAGA: Ta metoda jest przydatna tylko wtedy, gdy Twoja aplikacja / Działanie / zadanie jest jedynym procesem, który uzyska dostęp do Twojej usługi. Jeśli tak nie jest, musisz użyć opcji 1. lub 2.

MrSnowflake
źródło
2
Jak mogę wykonać busy-waitdziałanie? Czy możesz to wyjaśnić?
iTurki
1
Więc po onCreate lub po onStartCommand w twojej klasie usług ustaw publiczną zmienną statyczną, nazwij ją isConnected lub coś z prawdą. Następnie w swojej działalności wykonaj następujące czynności: Intent intent = new Intent (act, YourService.class); startService (intent); while (! YourService.isConnected) {sleep (300); } Po tej pętli usługa jest uruchomiona i możesz się z nią komunikować. Z mojego doświadczenia wynika, że ​​istnieją pewne ograniczenia w interakcji z taką usługą.
Matt Wolfe,
Dlaczego można go uruchomić tylko w Activity.onCreate()?
skywall
Jakieś słowo na temat tego, dlaczego nie chcesz używać Intents, wysyłając dane Parcellablemiędzy wiadomościami?
Aman Alam,
2
To działa, ale odpowiedź @ MaximumGoat jest znacznie bardziej przejrzysta i nie wymaga żadnego zajętego oczekiwania.
Matt
262

Pytający zapewne już dawno temu przeszedł, ale na wypadek, gdyby ktoś szukał tego ...

Jest inny sposób na poradzenie sobie z tym, który moim zdaniem może być najprostszy.

Dodaj a BroadcastReceiverdo swojej aktywności. Zarejestruj go, aby otrzymać niestandardowe zamiary onResumei wyrejestruj goonPause . Następnie wyślij ten zamiar ze swojej usługi, jeśli chcesz wysłać aktualizacje statusu lub co masz.

Upewnij się, że nie będziesz nieszczęśliwy, jeśli jakaś inna aplikacja wysłucha Twojej Intent(czy ktoś może zrobić coś złośliwego?), Ale poza tym powinieneś być w porządku.

Zażądano próbki kodu:

W mojej służbie mam to:

// Do stuff that alters the content of my local SQLite Database
sendBroadcast(new Intent(RefreshTask.REFRESH_DATA_INTENT));

( RefreshTask.REFRESH_DATA_INTENTjest tylko ciągiem ciągłym).

W mojej działalności związanej ze słuchaniem definiuję swoje BroadcastReceiver:

private class DataUpdateReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(RefreshTask.REFRESH_DATA_INTENT)) {
          // Do stuff - maybe update my view based on the changed DB contents
        }
    }
}

Deklaruję mój odbiornik na szczycie klasy:

private DataUpdateReceiver dataUpdateReceiver;

Zastępuję, onResumeaby dodać to:

if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(RefreshTask.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);

I zastępuję, onPauseaby dodać:

if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver);

Teraz moja aktywność oczekuje, że moja usługa powie „Hej, idź się zaktualizuj”. Mogę przekazywać dane Intentzamiast aktualizować tabele bazy danych, a następnie wracać, aby znaleźć zmiany w ramach mojej działalności, ale ponieważ chcę, aby zmiany nadal się utrzymywały, sensowne jest przekazywanie danych przez DB.

MaximumGoat
źródło
5
W jaki sposób? To, co opisujesz, jest dokładnie tym, czego potrzebuję. Co więcej, potrzebuję pełnego przykładowego kodu. Z góry dziękuję. Do Twojej wiadomości, kiedy ostatni raz próbowałem napisać widget, część wiadomości zajęła mi 2 miesiące. Śmiej się, jeśli chcesz, ale eksperci muszą publikować więcej, ponieważ IMHO Android jest bardziej skomplikowane niż iOS!
1
aaaaaaa, The Busy Coder's Guide to Advanced Android Development ma doskonały rozdział na temat widżetów. To jedyny zasób, który przeprowadził mnie przez ten bałagan. CommonsWare, autor, ma reputację 115K na StackOverflow i bardzo polecam książkę. commonsware.com/AdvAndroid
MaximumGoat
64
Broadcastssą fantastyczne, a ponadto, jeśli nie chcesz, aby transmisja wykraczała poza własny proces, rozważ użycie LocalBroadcast: developer.android.com/reference/android/support/v4/content/…
Cody Caughlan
2
Dzięki Cody, nie widziałem tego wcześniej.
MaximumGoat
3
To bardzo dobry sposób komunikacji. Ale co zrobić, jeśli wyniki zostały dostarczone, gdy aktywność była wstrzymana? Tak więc po aktywności onResume może długo czekać na wyniki. I żadne dane nie zostaną odebrane, ponieważ dane zostały pominięte.
Anton-M
39

Służy LocalBroadcastManagerdo rejestrowania odbiornika w celu nasłuchiwania transmisji wysyłanej z lokalnego serwisu w Twojej aplikacji, odnośnik znajduje się tutaj:

http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html

Jack Gao
źródło
3
Tak, bardzo miła dyskusja na temat transmisji lokalnej tutaj link
SohailAziz
1
LocalBroadcastManagerjest teraz przestarzałe na rzecz LiveDatalub innych narzędzi wzorców obserwatora: developer.android.com/reference/androidx/localbroadcastmanager/…
Ali Nem
20

Dziwi mnie, że nikt nie wspomniał o bibliotece Bus wydarzenie Otto

http://square.github.io/otto/

Używam tego w moich aplikacjach na Androida i działa bezproblemowo.

Madhur Ahuja
źródło
7
Alternatywnie istnieje biblioteka EventBus Greenrobota .
Jazzer
15
Pamiętaj jednak, że EventBus i otto są zawsze w jednym procesie. Gdy korzystasz z usługi, która jest w trakcie procesu (zaczęło się od ustawienia android:process=":my_service", nie mogą się komunikować.
Ron
20

Korzystanie z komunikatora to kolejny prosty sposób komunikowania się między usługą a działaniem.

W działaniu utwórz moduł obsługi z odpowiednim komunikatorem. Będzie to obsługiwać wiadomości z Twojej Usługi.

class ResponseHandler extends Handler {
    @Override public void handleMessage(Message message) {
            Toast.makeText(this, "message from service",
                    Toast.LENGTH_SHORT).show();
    }
}
Messenger messenger = new Messenger(new ResponseHandler());

Komunikator można przekazać do usługi, dołączając go do wiadomości:

Message message = Message.obtain(null, MyService.ADD_RESPONSE_HANDLER);
message.replyTo = messenger;
try {
    myService.send(message);
catch (RemoteException e) {
    e.printStackTrace();
}

Pełny przykład można znaleźć w prezentacjach API: MessengerService i MessengerServiceActivity . Zapoznaj się z pełnym przykładem działania MyService.

Kjetil
źródło
1
Bardzo mile widziane! Działa świetnie. Tylko szczegół w kodzie: myService.send(message);powinien być messenger.send(message);zamiast.
Federico Cristina,
9

Inną metodą, która nie została wymieniona w innych komentarzach, jest powiązanie usługi z działaniem za pomocą bindService () i uzyskanie wystąpienia usługi w wywołaniu zwrotnym ServiceConnection. Jak opisano tutaj http://developer.android.com/guide/components/bound-services.html

miguel
źródło
4
Jest to właściwy sposób uzyskania odniesienia do instancji usługi.
김준호
9

Możesz także użyć, LiveDataktóry działa jak EventBus.

class MyService : LifecycleService() {
    companion object {
        var BUS = MutableLiveData<Object>()
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)

        val testItem : Object

        // expose your data
        if (BUS.hasActiveObservers()) {
            BUS.postValue(testItem)
        }

        return START_NOT_STICKY
    }
}

Następnie dodaj obserwatora z twojego Activity.

MyService.BUS.observe(this, Observer {
    it?.let {
        // Do what you need to do here
    }
})

Możesz przeczytać więcej z tego bloga.

zeenozaur
źródło
2

Innym sposobem może być użycie obserwatorów z fałszywą klasą modelu poprzez działanie i samą usługę, implementując odmianę wzoru MVC. Nie wiem, czy to najlepszy sposób, aby to osiągnąć, ale tak mi się to udało. Jeśli potrzebujesz jakiegoś przykładu, poproś o to, a ja coś opublikuję.

Przeadresować__
źródło
Walczę z podobną myślą. Mam działalność i 2 usługi, które mają ten sam model. Model można zaktualizować w działaniu lub dowolnej z tych usług, więc pomyślałem o użyciu obserwatora, ale nie mogę go rozgryźć. Czy możesz podać przykład, aby pokazać swój pomysł?
pzo
2

Moja metoda:

Klasa zarządzająca wysyłaniem i odbieraniem wiadomości od / do usługi / działalności:

import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

public class MessageManager {

    public interface IOnHandleMessage{
        // Messages
        int MSG_HANDSHAKE = 0x1;

        void onHandleMessage(Message msg);
    }

    private static final String LOGCAT = MessageManager.class.getSimpleName();

    private Messenger mMsgSender;
    private Messenger mMsgReceiver;
    private List<Message> mMessages;

    public MessageManager(IOnHandleMessage callback, IBinder target){
        mMsgReceiver = new Messenger(new MessageHandler(callback, MessageHandler.TYPE_ACTIVITY));
        mMsgSender = new Messenger(target);
        mMessages = new ArrayList<>();
    }

    public MessageManager(IOnHandleMessage callback){
        mMsgReceiver = new Messenger(new MessageHandler(callback, MessageHandler.TYPE_SERVICE));
        mMsgSender = null;
        mMessages = new ArrayList<>();
    }

    /* START Getter & Setter Methods */
    public Messenger getMsgSender() {
        return mMsgSender;
    }

    public void setMsgSender(Messenger sender) {
        this.mMsgSender = sender;
    }

    public Messenger getMsgReceiver() {
        return mMsgReceiver;
    }

    public void setMsgReceiver(Messenger receiver) {
        this.mMsgReceiver = receiver;
    }

    public List<Message> getLastMessages() {
        return mMessages;
    }

    public void addMessage(Message message) {
        this.mMessages.add(message);
    }
    /* END Getter & Setter Methods */

    /* START Public Methods */
    public void sendMessage(int what, int arg1, int arg2, Bundle msgData){
        if(mMsgSender != null && mMsgReceiver != null) {
            try {
                Message msg = Message.obtain(null, what, arg1, arg2);
                msg.replyTo = mMsgReceiver;
                if(msgData != null){
                    msg.setData(msgData);
                }
                mMsgSender.send(msg);
            } catch (RemoteException rE) {
                onException(rE);
            }
        }
    }

    public void sendHandshake(){
        if(mMsgSender != null && mMsgReceiver != null){
            sendMessage(IOnHandleMessage.MSG_HANDSHAKE, 0, 0, null);
        }
    }
    /* END Public Methods */

    /* START Private Methods */
    private void onException(Exception e){
        Log.e(LOGCAT, e.getMessage());
        e.printStackTrace();
    }
    /* END Private Methods */

    /** START Private Classes **/
    private class MessageHandler extends Handler {

        // Types
        final static int TYPE_SERVICE = 0x1;
        final static int TYPE_ACTIVITY = 0x2;

        private IOnHandleMessage mCallback;
        private int mType;

        public MessageHandler(IOnHandleMessage callback, int type){
            mCallback = callback;
            mType = type;
        }

        @Override
        public void handleMessage(Message msg){
            addMessage(msg);
            switch(msg.what){
                case IOnHandleMessage.MSG_HANDSHAKE:
                    switch(mType){
                        case TYPE_SERVICE:
                            setMsgSender(msg.replyTo);
                            sendHandshake();
                            break;
                        case TYPE_ACTIVITY:
                            Log.v(LOGCAT, "HERE");
                            break;
                    }
                    break;
                default:
                    if(mCallback != null){
                        mCallback.onHandleMessage(msg);
                    }
                    break;
            }
        }

    }
    /** END Private Classes **/

}

W przykładzie działania:

public class activity extends AppCompatActivity
      implements     ServiceConnection,
                     MessageManager.IOnHandleMessage { 

    [....]

    private MessageManager mMessenger;

    private void initMyMessenger(IBinder iBinder){
        mMessenger = new MessageManager(this, iBinder);
        mMessenger.sendHandshake();
    }

    private void bindToService(){
        Intent intent = new Intent(this, TagScanService.class);
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        /* START THE SERVICE IF NEEDED */
    }

    private void unbindToService(){
    /* UNBIND when you want (onDestroy, after operation...)
        if(mBound) {
            unbindService(mServiceConnection);
            mBound = false;
        }
    }

    /* START Override MessageManager.IOnHandleMessage Methods */
    @Override
    public void onHandleMessage(Message msg) {
        switch(msg.what){
            case Constants.MSG_SYNC_PROGRESS:
                Bundle data = msg.getData();
                String text = data.getString(Constants.KEY_MSG_TEXT);
                setMessageProgress(text);
                break;
            case Constants.MSG_START_SYNC:
                onStartSync();
                break;
            case Constants.MSG_END_SYNC:
                onEndSync(msg.arg1 == Constants.ARG1_SUCCESS);
                mBound = false;
                break;
        }
    }
    /* END Override MessageManager.IOnHandleMessage Methods */

    /** START Override ServiceConnection Methods **/
    private class BLEScanServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            initMyMessenger(iBinder);
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mMessenger = null;
            mBound = false;
        }
    }
    /** END Override ServiceConnection Methods **/

W przykładzie serwisowym:

public class Blablabla extends Service
    implements     MessageManager.IOnHandleMessage {

    [...]

    private MessageManager mMessenger;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        super.onBind(intent);
        initMessageManager();
        return mMessenger.getMsgReceiver().getBinder();
    }

    private void initMessageManager(){
        mMessenger = new MessageManager(this);
    }

    /* START Override IOnHandleMessage Methods */
    @Override
    public void onHandleMessage(Message msg) {
    /* Do what you want when u get a message looking the "what" attribute */
    }
    /* END Override IOnHandleMessage Methods */

Wyślij wiadomość z działania / usługi:

mMessenger.sendMessage(what, arg1, arg2, dataBundle);

Jak to działa:

na działalność, którą uruchamiasz lub wiążesz z usługą. Metody usługi „OnBind” zwracają Binder do jego menedżera komunikatów MessageManager, aw działaniu poprzez implementację metod interfejsu „Połączenie usługi” „OnServiceConnected” dostajesz tego IBindera i inicjujesz korzystanie z niego przy pomocy menedżera komunikatów. Po zainicjowaniu działania MessageManager przez MessageHandler, usługa MessageHandler wysyła i uzgadnia z serwisem, aby mógł ustawić swojego nadawcę „MessageHandler” („private Messenger mMsgSender;” w MessageManager). W ten sposób usługa wie, kto wysyła jego wiadomości.

Można to również zaimplementować za pomocą „nadawcy” listy / kolejki komunikatora w menedżerze wiadomości, aby można było wysyłać wiele wiadomości do różnych działań / usług lub można użyć „odbiornika” listy / kolejki komunikatora w menedżerze wiadomości, aby otrzymywać wiele wiadomość z różnych działań / usług.

W instancji „MessageManager” masz listę wszystkich otrzymanych wiadomości.

Jak widać połączenie między „Activity's Messenger” a „Service Messenger” za pomocą tego wystąpienia „MessageManager” odbywa się automatycznie, odbywa się to za pomocą metody „OnServiceConnected” i za pomocą „Handshake”.

Mam nadzieję, że jest to dla ciebie pomocne :) Dziękuję bardzo! Pa: D

Z3R0
źródło
2

Aby śledzić odpowiedź @MrSnowflake na przykładzie kodu. To jest teraz Applicationklasa open source XABBER . ApplicationKlasa centralizację i koordynowanie Listenersi ManagerInterfaces i więcej. Menedżerowie wszelkiego rodzaju są ładowani dynamicznie. Activity´srozpoczęty w Xabber zgłosi, jakiego rodzaju Listenersą. A kiedy Servicezaczyna, raportuje do Applicationklasy, jak zaczął. Teraz, aby wysłać wiadomość na Activitywszystko, co musisz zrobić, to twój Activitystały się listenerod tego, co trzeba wpisać. W OnStart() OnPause()rejestrze / unreg. ServiceMoże zwrócić się do Applicationklasy dla tylko, że listenerto trzeba mówić do i jeśli jest tam wtedy aktywny jest gotowy do odbioru.

Przechodząc przez Applicationklasę zobaczysz, że dzieje się coś więcej niż to.

Erik
źródło
Podany link powoduje teraz utworzenie github 404. Czy się poruszył?
JE Carter II,
Tak, wydaje się teraz działać. To musiał być tymczasowy problem na github.
JE Carter II,
1

Wiązanie to kolejny sposób komunikacji

Utwórz połączenie zwrotne

public interface MyCallBack{

   public void getResult(String result);

}

Strona aktywności:

  1. Zaimplementuj interfejs w działaniu

  2. Podaj implementację metody

  3. Powiąż działanie z usługą

  4. Zarejestruj się i wyrejestruj oddzwonienie, gdy usługa zostanie powiązana i niezwiązana z Działaniem.

    public class YourActivity extends AppCompatActivity implements MyCallBack{
    
          private Intent notifyMeIntent;
          private GPSService gpsService;
          private boolean bound = false;
    
          @Override
          public void onCreate(Bundle sis){
    
              // activity code ...
    
              startGPSService();
    
          }
    
          @Override
          public void getResult(String result){
           // show in textView textView.setText(result);
          }
    
          @Override
          protected void onStart()
          {
              super.onStart();
              bindService();
          }
    
          @Override
          protected void onStop() {
              super.onStop();
              unbindService();
          }
    
          private ServiceConnection serviceConnection = new ServiceConnection() {
    
                @Override
                public void onServiceConnected(ComponentName className, IBinder service) {
    
                      GPSService.GPSBinder binder = (GPSService.GPSBinder) service;
                      gpsService= binder.getService();
                      bound = true;
                      gpsService.registerCallBack(YourActivity.this); // register
    
               }
    
               @Override
               public void onServiceDisconnected(ComponentName arg0) {
                      bound = false;
               }
          };
    
          private void bindService() {
    
               bindService(notifyMeIntent, serviceConnection, Context.BIND_AUTO_CREATE);
          }
    
          private void unbindService(){
               if (bound) {
                     gpsService.registerCallBack(null); // unregister            
                     unbindService(serviceConnection);
                     bound = false;
                }
          }
    
          // Call this method somewhere to start Your GPSService
          private void startGPSService(){
               notifyMeIntent = new Intent(this, GPSService.class);
               startService(myIntent );
          }
    
     }

Strona serwisowa:

  1. Zainicjuj oddzwonienie

  2. W razie potrzeby wywołuj metodę wywołania zwrotnego

     public class GPSService extends Service{
    
         private MyCallBack myCallback;
         private IBinder serviceBinder = new GPSBinder();
    
         public void registerCallBack(MyCallBack myCallback){
              this.myCallback= myCallback;
         }
    
         public class GPSBinder extends Binder{
    
             public GPSService getService(){
                  return GPSService.this;
             }
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent){
             return serviceBinder;
        }
     }
Rohit Singh
źródło
twój serviceConnectionjest z onCreate. Edytuj to.
Adeel Zafar
Nie musi znajdować się w witrynie Create
Rohit Singh
0

Oprócz LocalBroadcastManager, Event Bus i Messenger już odpowiedział na to pytanie, możemy użyć Pending Intent do komunikacji z serwisu.

Jak wspomniano tutaj w moim blogu

Komunikacja między usługą a działaniem może odbywać się za pomocą PendingIntent. Do tego możemy użyć createPendingResult () .createPendingResult () tworzy nowy obiekt PendingIntent, który możesz oddać do obsługi i wysłać dane wyników z powrotem do swojej aktywności wewnątrz onActivityResult (int, int, Intent) oddzwanianie Ponieważ PendingIntent jest paczkowany, a zatem można go zamienić na dodatek Intent, twoja aktywność może przekazać ten PendingIntent do usługi. Z kolei usługa może wywołać metodę send () w PendingIntent, aby powiadomić aktywność poprzez onActivityResult zdarzenia.

Czynność

public class PendingIntentActivity extends AppCompatActivity
{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

PendingIntent pendingResult = createPendingResult(
100, new Intent(), 0);
Intent intent = new Intent(getApplicationContext(), PendingIntentService.class);
intent.putExtra("pendingIntent", pendingResult);
startService(intent);

}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 100 && resultCode==200) {
Toast.makeText(this,data.getStringExtra("name"),Toast.LENGTH_LONG).show();
}
super.onActivityResult(requestCode, resultCode, data);
}
}

Usługa

public class PendingIntentService extends Service {

    private static final String[] items= { "lorem", "ipsum", "dolor",
            "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi",
            "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam",
            "vel", "erat", "placerat", "ante", "porttitor", "sodales",
            "pellentesque", "augue", "purus" };
    private PendingIntent data;

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        data = intent.getParcelableExtra("pendingIntent");

        new LoadWordsThread().start();
        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

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

    class LoadWordsThread extends Thread {
        @Override
        public void run() {
            for (String item : items) {
                if (!isInterrupted()) {

                    Intent result = new Intent();
                    result.putExtra("name", item);
                    try {
                        data.send(PendingIntentService.this,200,result);
                    } catch (PendingIntent.CanceledException e) {

                        e.printStackTrace();
                    }
                    SystemClock.sleep(400);

                }
            }
        }
    }
}
Programista Androida
źródło