Android: So lösen Sie sicher einen Dienst

Lesezeit: 6 Minuten

Benutzer-Avatar
2. Leben

Ich habe einen Dienst, der wie folgt an den Anwendungskontext gebunden ist:

getApplicationContext().bindService(
                    new Intent(this, ServiceUI.class),
                    serviceConnection,
                    Context.BIND_AUTO_CREATE
            );

protected void onDestroy() {
            super.onDestroy();                  
            getApplicationContext().unbindService(serviceConnection);
        }

Aus irgendeinem Grund wird der Anwendungskontext nur manchmal nicht richtig gebunden (ich kann diesen Teil nicht reparieren), aber in onDestroy() tue ich es unbindservice was einen Fehler auslöst

java.lang.IllegalArgumentException: Service not registered: tools.cdevice.Devices$mainServiceConnection.

Meine Frage ist: Gibt es eine Möglichkeit anzurufen? unbindservice sicher oder überprüfen Sie, ob es bereits an einen Dienst gebunden ist, bevor Sie die Bindung aufheben?

Danke im Voraus.

  • überprüfen Sie stackoverflow.com/questions/1916253/…

    – Sunil Kumar Sahoo

    23. Dezember 2011 um 9:43 Uhr

  • Ich habe das schon einmal durchgemacht, aber das löst mein Problem nicht, sagen wir einfach, dass ich UnBindService aufrufe, ohne BindService() aufzurufen, wie gehen Sie mit dem Fehler ohne den Anwendungs-FC um?

    – 2. Leben

    23. Dezember 2011 um 12:28 Uhr

  • Könnten Sie nicht einfach die Ausnahme abfangen und weitermachen?

    – Drachenwurzel

    15. Januar 2012 um 21:05 Uhr

  • @Yurys Antwort ist die richtige Antwort.

    – Vans Fannel

    6. August 2012 um 16:41 Uhr

  • Dies liegt daran, dass Sie den Dienst mit getApplicationContext() binden und ihn dann mit dem aktuellen Aktivitätskontext lösen. Es ist, als würde man X eine Münze geben und Y danach fragen. Es wird eine IllegarlArgumentException auslösen 🙂 Ich hoffe, dies ist die Antwort auf die Frage, verwenden Sie denselben Kontext beim Binden und Aufheben 🙂

    – AZ_

    23. Januar 2014 um 13:07 Uhr

Benutzer-Avatar
Andrej Nowikow

Versuche dies:

boolean isBound = false;
...
isBound = getApplicationContext().bindService( new Intent(getApplicationContext(), ServiceUI.class), serviceConnection, Context.BIND_AUTO_CREATE );
...
if (isBound)
    getApplicationContext().unbindService(serviceConnection);

Notiz:

Sie sollten dasselbe verwenden context zum Binden eines Dienstes und zum Entbinden eines Dienstes. Bei verbindlichem Service mit getApplicationContext() also solltest du auch verwenden getApplicationContext.unbindService(..)

  • Ich habe Ihre Antwort befolgt und erhalte immer noch den gleichen Fehler. @Yury antworte, behebe das Problem.

    – Vans Fannel

    6. August 2012 um 16:40 Uhr

  • beide Antworten sind richtig: die von Andrey Novikov und @Yury

    – Snikola

    8. August 2012 um 12:42 Uhr

  • Es scheint mir, dass diese Lösung den gebundenen Dienst lecken würde, weil ich gerade herausgefunden habe, dass das Entbinden im selben Kontext aufgerufen werden muss. Das Testen in einem anderen Kontext kann also zu seltsamen Ergebnissen führen, wenn tatsächlich zweimal an einen bestimmten Dienst gebunden wurde (wenn überhaupt möglich?).

    – 3c71

    22. Januar 2014 um 4:27 Uhr

  • Ich habe verstanden, warum ich das gelesen habe: stackoverflow.com/questions/10641144/…

    – fersarr

    7. März 2014 um 7:24 Uhr


  • Mein Problem schien auf die Verwendung des Aktivitätskontexts anstelle des Anwendungskontexts zurückzuführen zu sein. Um zu verhindern, dass der von Ihnen verwendete Kontext verpfuscht wird, stellen Sie wie erwähnt sicher, dass Sie den Anwendungskontext für alle Bindungen/Aufhebungen verwenden.

    – ian.shaun.thomas

    27. Januar 2016 um 15:13 Uhr

Benutzer-Avatar
Juri

Hier Sie können eine nette Erklärung und Quellcodes finden, wie man mit gebundenen Diensten arbeitet. In Ihrem Fall sollten Sie Methoden überschreiben (onServiceConnected und onServiceDisconnected) von ServiceConnection Objekt. Dann kannst du einfach nachschauen mBound Variable in Ihrem Code.

  • Ich fürchte, das angegebene Beispiel bezieht sich auf lokale Dienste, nicht auf entfernte Prozessdienste.

    – Surya Wijaya Madjid

    16. Oktober 2012 um 8:28 Uhr

  • Im Gegensatz zum lokalen wird uns die Bindung an Remote-Dienste geben onServiceDisconnected() Rückruf, wenn der Prozess des Zieldienstes stirbt und onServiceConnected() wird nach einem Neustart erneut geliefert. Wenn Sie sich auf diese Rückrufe für die verlassen mBound -Flag erhalten Sie ein Dienstverbindungsleck, wenn der Versuch, die Bindung aufzuheben, dazwischen erfolgt onServiceDisconnected() und onServiceConnected() wenn der mBound wäre false.

    – Surya Wijaya Madjid

    16. Oktober 2012 um 8:29 Uhr

  • Um dieses Problem zu lösen, setzen Sie mBound unter onServiceDisconnected nicht auf false. Und wenn es notwendig ist, verbundene und getrennte Status zu verfolgen, führen Sie vielleicht eine weitere Variable mConnected ein.

    – Kevin Lee

    8. April 2016 um 19:24 Uhr

  • 404. Antworten, die Links anstelle von Auszügen posten, sollten wirklich gefördert werden

    – mr5

    22. Juni 2016 um 8:08 Uhr

Benutzer-Avatar
Emil Blablabla

Genau das zu tun, was Andrey Novikov vorgeschlagen hat, hat für mich nicht funktioniert. Ich habe einfach ersetzt:

getApplicationContext().unbindService(serviceConnection);

Mit:

unbindService(serviceConnection);

  • Was ist ServiceVerbindung?

    – IgorGanapolsky

    27. Oktober 2017 um 19:42 Uhr

Ich habe festgestellt, dass es zwei Probleme gibt. Mehr als einmal zu binden und auch mehr als einmal zu lösen.

Lösung:

public class ServiceConnectionManager implements ServiceConnection {

    private final Context context;
    private final Class<? extends Service> service;
    private boolean attemptingToBind = false;
    private boolean bound = false;

    public ServiceConnectionManager(Context context, Class<? extends Service> service) {
        this.context = context;
        this.service = service;
    }

    public void bindToService() {
        if (!attemptingToBind) {
            attemptingToBind = true;
            context.bindService(new Intent(context, service), this, Context.BIND_AUTO_CREATE);
        }
    }

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        attemptingToBind = false;
        bound = true;
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        bound = false;
    }

    public void unbindFromService() {
        attemptingToBind = false;
        if (bound) {
            context.unbindService(this);
            bound = false;
        }
    }

}

Warum erhalten wir diesen Fehler?

Wenn Sie versuchen, einen nicht registrierten Dienst abzumelden.

Was sind einige gängige Beispiele?

  • Bindung und Bindung eines Dienstes mit unterschiedlichem Kontext aufheben.
  • Berufung unBind(mserviceConnection) mehr als bind(...)

Der erste Punkt ist selbsterklärend. Lassen Sie uns die zweite Fehlerquelle genauer untersuchen. Debuggen Sie Ihre bind()- und unbind()-Aufrufe. Wenn Sie Anrufe in dieser Reihenfolge sehen, erhält Ihre Anwendung die IllegalArgumentException.

Geben Sie hier die Bildbeschreibung ein

Wie können wir das vermeiden?

Es gibt zwei Möglichkeiten, einen Dienst in Activity zu binden und zu entbinden. Android-Dokumente empfehlen das

  • Wenn Sie nur dann mit einem Dienst interagieren möchten, wenn die Aktivität sichtbar ist

bindService() ein onStart() und unbindService() ein onStop()

Your Activity {

    @Override
    public void onStart(){
       super.onStart();
       bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
    }

    @Override
    public void onStop(){
       super.onStop();
       unbindService(mConnection);
    }

} 
  • Wenn Sie mit einem Dienst interagieren möchten, befindet sich sogar eine Aktivität im Hintergrund

bindService() ein onCreate() und unbindService() ein onDestroy()

Your Activity {

    @Override
    public void onCreate(Bindle sis){
       super.onCreate(sis);
        ....
        bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
    }

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

}

Benutzer-Avatar
Gemeinschaft

ich denke, dass führen ist nicht ganz korrekt wie hier erwähnt Surya Wijaya Madjid. Speicherverluste können auftreten, wenn der gebundene Dienst zerstört und noch nicht wieder verbunden ist.

Ich denke, dass dieser Ansatz erforderlich ist:

Service mService;

private final ServiceConnection mServiceConnection = new ServiceConnection()
{
    boolean bound = false;

    @Override
    public void onServiceDisconnected(ComponentName name)
    {
        mService = null;
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service)
    {
        mService = ((MyService.ServiceBinder) service).getService();

        if (!bound)
        {
            // do some action - service is bound for the first time
            bound = true;
        }
    }
};

@Override
public void onDestroy()
{
    if (mService != null)
    {
        // do some finalization with mService
    }

    if (mServiceConnection.bound)
    {
        mServiceConnection.bound = false;
        unbindService(mServiceConnection);
    }
    super.onDestroy();
}

public void someMethod()
{
    if (mService != null)
    {
        // to test whether Service is available, I have to test mService, not     mServiceConnection.bound
    }
}

Benutzer-Avatar
Jiaqi Jiang

Verwenden Sie eine Variable, um aufzuzeichnen, ob Sie sich jemals an einen Dienst gebunden haben, und lösen Sie die Bindung, wenn die Variable wahr ist.

Siehe offizielles Android-Beispiel:

http://androidxref.com/9.0.0_r3/xref/development/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java#376

1038620cookie-checkAndroid: So lösen Sie sicher einen Dienst

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

Privacy policy