So kommuniziert der Android-Dienst mit Activity

Lesezeit: 8 Minuten

So kommuniziert der Android Dienst mit Activity
Scott Saunders

Ich schreibe meine erste Android-Anwendung und versuche, mich mit der Kommunikation zwischen Diensten und Aktivitäten vertraut zu machen. Ich habe einen Dienst, der im Hintergrund läuft und einige GPS- und zeitbasierte Protokollierungen durchführt. Ich werde eine Aktivität haben, die verwendet wird, um den Dienst zu starten und zu stoppen.

Also muss ich zuerst herausfinden können, ob der Dienst ausgeführt wird, wenn die Aktivität gestartet wird. Es gibt hier einige andere Fragen dazu, also denke ich, dass ich das herausfinden kann (aber Sie können gerne Ratschläge geben).

Mein eigentliches Problem: Wenn die Aktivität ausgeführt wird und der Dienst gestartet ist, brauche ich eine Möglichkeit für den Dienst, Nachrichten an die Aktivität zu senden. An dieser Stelle einfache Strings und Integer – meistens Statusmeldungen. Die Nachrichten werden nicht regelmäßig angezeigt, daher denke ich nicht, dass das Abrufen des Dienstes ein guter Weg ist, wenn es einen anderen Weg gibt. Ich möchte diese Kommunikation nur, wenn die Aktivität vom Benutzer gestartet wurde – ich möchte die Aktivität nicht vom Dienst aus starten. Mit anderen Worten, wenn Sie die Aktivität starten und der Dienst ausgeführt wird, sehen Sie einige Statusmeldungen in der Aktivitäts-Benutzeroberfläche, wenn etwas Interessantes passiert. Wenn Sie die Aktivität nicht starten, werden Sie diese Nachrichten nicht sehen (sie sind nicht so interessant).

Es scheint, als sollte ich feststellen können, ob der Dienst ausgeführt wird, und wenn ja, die Aktivität als Listener hinzufügen. Entfernen Sie dann die Aktivität als Listener, wenn die Aktivität angehalten oder beendet wird. Ist das tatsächlich möglich? Die einzige Möglichkeit, dies zu tun, besteht darin, die Aktivität Parcelable zu implementieren und eine AIDL-Datei zu erstellen, damit ich sie über die Remoteschnittstelle des Diensts übergeben kann. Das scheint jedoch übertrieben zu sein, und ich habe keine Ahnung, wie die Aktivität writeToParcel() / readFromParcel() implementieren soll.

Gibt es einen einfacheren oder besseren Weg? Danke für jede Hilfe.

BEARBEITEN:

Für alle, die sich später dafür interessieren, gibt es Beispielcode von Google, um dies über AIDL zu handhaben, im Beispielverzeichnis: /apis/app/RemoteService.java

1646632391 182 So kommuniziert der Android Dienst mit Activity
MaximumZiege

Der Fragesteller ist wahrscheinlich schon lange darüber hinweg, aber falls jemand anderes danach sucht …

Es gibt eine andere Möglichkeit, damit umzugehen, die meiner Meinung nach die einfachste sein könnte.

Füge hinzu ein BroadcastReceiver zu Ihrer Tätigkeit. Registrieren Sie es, um eine benutzerdefinierte Absicht zu erhalten onResume und deregistrieren Sie es in onPause. Senden Sie dann diese Absicht von Ihrem Dienst aus, wenn Sie Ihre Statusaktualisierungen oder was auch immer senden möchten.

Stellen Sie sicher, dass Sie nicht unglücklich wären, wenn eine andere App auf Ihre hören würde Intent (Könnte jemand etwas Bösartiges tun?), Aber darüber hinaus sollte es Ihnen gut gehen.

Codebeispiel wurde angefordert:

In meinem Dienst habe ich Folgendes:

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

(RefreshTask.REFRESH_DATA_INTENT ist nur eine konstante Zeichenfolge.)

In meiner Zuhörtätigkeit definiere ich meine 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
        }
    }
}

Ich erkläre meinen Empfänger an der Spitze der Klasse:

private DataUpdateReceiver dataUpdateReceiver;

ich überschreite onResume um das hinzuzufügen:

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

Und ich überschreite onPause hinzufügen:

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

Jetzt wartet meine Aktivität darauf, dass mein Dienst sagt: “Hey, aktualisiere dich selbst.” Ich könnte Daten in die übergeben Intent Anstatt Datenbanktabellen zu aktualisieren und dann zurückzugehen, um die Änderungen innerhalb meiner Aktivität zu finden, aber da ich die Änderungen sowieso beibehalten möchte, ist es sinnvoll, die Daten über DB zu übergeben.

  • Wie? Was du beschreibst ist genau das was ich brauche. Aber darüber hinaus benötige ich vollständigen Beispielcode. Vielen Dank im Voraus. FYI, das letzte Mal, als ich versuchte, ein Widget zu schreiben, dauerte der Messaging-Teil 2 Monate. Lachen Sie, wenn Sie wollen, aber Sie Experten müssen mehr veröffentlichen, da Android meiner Meinung nach komplizierter ist als iOS!

    Benutzer407749

    27. Juli 2011 um 20:54 Uhr


  • aaaaaaa, The Busy Coder’s Guide to Advanced Android Development hat ein ausgezeichnetes Kapitel über Widgets. Es ist die einzige Ressource, die mich durch diesen Schlamassel gebracht hat. CommonsWare, der Autor, hat einen Ruf von 115.000 auf StackOverflow, und ich kann das Buch nur wärmstens empfehlen. commonsware.com/AdvAndroid

    – MaximumZiege

    9. August 2011 um 19:08 Uhr

  • Broadcasts sind fantastisch und wenn Sie nicht möchten, dass Ihre Sendung über Ihren eigenen Prozess hinausgeht, sollten Sie die Verwendung von a in Betracht ziehen LocalBroadcast: developer.android.com/reference/android/support/v4/content/…

    – Cody Cauglan

    25. Februar 2012 um 21:26 Uhr

  • Danke Cody, das hatte ich noch nie gesehen.

    – MaximumZiege

    27. Februar 2012 um 22:22 Uhr

  • Das ist eine sehr gute Art der Kommunikation. Aber was tun, wenn Ergebnisse geliefert wurden, wenn die Aktivität pausiert war? Daher kann die Aktivität nach onResume lange auf Ergebnisse warten. Und es werden keine Daten empfangen, weil Daten ausgelassen wurden.

    – Anton-M

    20. April 2013 um 21:32 Uhr

1646632392 989 So kommuniziert der Android Dienst mit Activity
Herr Schneeflocke

Es gibt drei offensichtliche Möglichkeiten, mit Diensten zu kommunizieren:

  1. Absichten verwenden
  2. Verwenden von AIDL
  3. Verwenden des Dienstobjekts selbst (als Singleton)

In Ihrem Fall würde ich mich für Option 3 entscheiden. Stellen Sie einen statischen Verweis auf den Dienst selbst her und füllen Sie ihn in onCreate () aus:

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

Erstellen Sie eine statische Funktion MyService getInstance()die die Statik zurückgibt sInstance.

Dann in Activity.onCreate() Sie starten den Dienst, warten asynchron, bis der Dienst tatsächlich gestartet ist (Sie könnten Ihren Dienst Ihrer App mitteilen, dass er bereit ist, indem Sie eine Absicht an die Aktivität senden.) und seine Instanz abrufen. Wenn Sie die Instanz haben, registrieren Sie Ihr Service-Listener-Objekt bei Ihrem Service, und schon sind Sie fertig. HINWEIS: Wenn Sie Ansichten innerhalb der Aktivität bearbeiten, sollten Sie sie im UI-Thread ändern, der Dienst wird wahrscheinlich seinen eigenen Thread ausführen, also müssen Sie ihn aufrufen Activity.runOnUiThread().

Das letzte, was Sie tun müssen, ist, den Verweis auf Ihr Listener-Objekt in zu entfernen Activity.onPause()andernfalls wird eine Instanz Ihres Aktivitätskontexts durchsickern, nicht gut.

HINWEIS: Diese Methode ist nur nützlich, wenn Ihre Anwendung/Aktivität/Aufgabe der einzige Prozess ist, der auf Ihren Dienst zugreift. Ist dies nicht der Fall, müssen Sie Option 1. oder 2. verwenden.

  • Wie kann ich busy-wait die Aktivität? Kannst du bitte erklären ?

    – iTurki

    24. Juli 2011 um 13:13 Uhr

  • Setzen Sie also entweder nach onCreate oder nach onStartCommand in Ihrer Dienstklasse eine öffentliche statische Variable, nennen Sie sie isConnected oder etwas auf true. Dann tun Sie dies in Ihrer Aktivität: Intent Intent = new Intent(act, YourService.class); startService(absicht); while(!YourService.isConnected) { sleep(300); } Nach dieser Schleife läuft Ihr Dienst und Sie können damit kommunizieren. Meiner Erfahrung nach gibt es definitiv einige Einschränkungen bei der Interaktion mit einem solchen Dienst.

    – Matt Wolfe

    28. Dezember 2011 um 1:10 Uhr


  • Warum es nur in gestartet werden kann Activity.onCreate()?

    – Himmelswand

    29. April 2012 um 22:50 Uhr

  • Irgendein Wort darüber, warum Sie es nicht verwenden möchten Intents durch Senden von Daten durch Parcellable Nachrichten zwischen ihnen?

    – Aman Alam

    14. Dezember 2012 um 7:09 Uhr

  • Das funktioniert, aber die Antwort von @MaximumGoat ist viel sauberer und erfordert kein geschäftiges Warten.

    – Matthew

    3. Juni 2013 um 18:46 Uhr


1646632393 111 So kommuniziert der Android Dienst mit Activity
Jack Gao

Verwenden LocalBroadcastManager Um einen Empfänger zu registrieren, um eine Sendung zu hören, die von einem lokalen Dienst in Ihrer App gesendet wird, finden Sie die Referenz hier:

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

Ich bin überrascht, dass niemand auf die Otto-Event-Bus-Bibliothek verwiesen hat

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

Ich habe dies in meinen Android-Apps verwendet und es funktioniert nahtlos.

1646632393 338 So kommuniziert der Android Dienst mit Activity
Kjetil

Die Verwendung eines Messengers ist eine weitere einfache Möglichkeit, zwischen einem Dienst und einer Aktivität zu kommunizieren.

Erstellen Sie in der Aktivität einen Handler mit einem entsprechenden Messenger. Dadurch werden Nachrichten von Ihrem Dienst verarbeitet.

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());

Der Messenger kann an den Dienst übergeben werden, indem er an eine Nachricht angehängt wird:

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

Ein vollständiges Beispiel finden Sie in den API-Demos: MessengerService und MessengerServiceActivity. Sehen Sie sich das vollständige Beispiel an, um zu erfahren, wie MyService funktioniert.

  • Sehr geschätzt! Funktioniert perfekt. Nur ein Detail im Code: myService.send(message); sollte sein messenger.send(message); stattdessen.

    – Federico Cristina

    3. August 2019 um 19:43 Uhr

So kommuniziert der Android Dienst mit Activity
Vlad

Sie können auch verwenden LiveData das funktioniert wie ein EventBus.

class MyService : LifecycleService() {
    companion object {
        val BUS = MutableLiveData<Any>()
    }

    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
    }
}

Dann fügen Sie einen Beobachter aus Ihrer hinzu Activity.

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

Daraus können Sie mehr lesen bloggen.

  • Sehr geschätzt! Funktioniert perfekt. Nur ein Detail im Code: myService.send(message); sollte sein messenger.send(message); stattdessen.

    – Federico Cristina

    3. August 2019 um 19:43 Uhr

1646632396 739 So kommuniziert der Android Dienst mit Activity
miguel

Die andere Methode, die in den anderen Kommentaren nicht erwähnt wird, besteht darin, mithilfe von bindService() von der Aktivität aus an den Dienst zu binden und eine Instanz des Diensts im ServiceConnection-Callback abzurufen. Wie hier beschrieben http://developer.android.com/guide/components/bound-services.html

  • Dies ist der richtige Weg, um die Referenz der Dienstinstanz zu erhalten.

    – 김준호

    21. Mai 2016 um 10:13 Uhr

963330cookie-checkSo kommuniziert der Android-Dienst mit Activity

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy