Suche…


Einführung

Ein Dienst wird im Hintergrund ausgeführt , um lange andauernde Vorgänge auszuführen oder um Arbeit für Remote-Prozesse auszuführen. Ein Dienst bietet keine Benutzeroberfläche, die nur im Hintergrund mit Benutzereingaben ausgeführt wird. Beispielsweise kann ein Dienst Musik im Hintergrund abspielen, während sich der Benutzer in einer anderen App befindet, oder er kann Daten aus dem Internet herunterladen, ohne die Interaktion des Benutzers mit dem Android-Gerät zu blockieren.

Bemerkungen

Wenn Sie Ihren Dienst nicht in Ihrer AndroidManifest.xml definiert haben, erhalten Sie beim Starten des Diensts eine ServiceNotFoundException .

Hinweis:

Informationen zu IntentService finden Sie hier: IntentService-Beispiel

Service starten

Das Starten eines Dienstes ist sehr einfach. Rufen startService einfach startService mit einer Absicht aus einer Aktivität heraus auf:

Intent intent = new Intent(this, MyService.class);  //substitute MyService with the name of your service
intent.putExtra(Intent.EXTRA_TEXT, "Some text"); //add any extra data to pass to the service

startService(intent); //Call startService to start the service.

Lebenszyklus eines Dienstes

Der Servicelebenszyklus hat die folgenden Rückrufe

  • onCreate() :

Wird ausgeführt, wenn der Service zum ersten Mal erstellt wird, um die erforderlichen Anfangskonfigurationen einzurichten. Diese Methode wird nur ausgeführt, wenn der Dienst noch nicht ausgeführt wird.

  • onStartCommand() :

startService() jedes Mal ausgeführt, wenn startService() von einer anderen Komponente wie einer Aktivität oder einem BroadcastReceiver aufgerufen wird. Wenn Sie diese Methode verwenden, wird der Dienst ausgeführt, bis Sie stopSelf() oder stopService() . Beachten Sie, dass die Methoden stopSelf() und stopService() nur einmal aufgerufen werden müssen, unabhängig davon, wie oft Sie onStartCommand() stopSelf() , um den Dienst zu stoppen.

  • onBind() :

bindService() ausgeführt, wenn eine Komponente bindService() und eine Instanz von IBInder zurückgibt, die einen Kommunikationskanal für den Service bereitstellt. Ein Aufruf von bindService() hält den Dienst so lange an, wie Clients daran gebunden sind.

  • onDestroy() :

Wird ausgeführt, wenn der Dienst nicht mehr verwendet wird, und ermöglicht die Entsorgung der zugewiesenen Ressourcen.

Es ist wichtig zu beachten, dass während des Lebenszyklus eines Diensts andere Callbacks aufgerufen werden können, z. B. onConfigurationChanged() und onLowMemory()

https://developer.android.com/guide/components/services.html

Geben Sie hier die Bildbeschreibung ein

Definieren des Prozesses eines Services

Das android:process Feld definiert den Namen des Prozesses, in dem der Dienst ausgeführt werden soll. Normalerweise werden alle Komponenten einer Anwendung in dem Standardprozess ausgeführt, der für die Anwendung erstellt wurde. Eine Komponente kann jedoch den Standardwert mit einem eigenen Prozessattribut überschreiben, sodass Sie Ihre Anwendung auf mehrere Prozesse verteilen können.

Wenn der diesem Attribut zugewiesene Name mit einem Doppelpunkt (':') beginnt, wird der Dienst in einem separaten Prozess ausgeführt.

<service
  android:name="com.example.appName"
  android:process=":externalProcess" />

Wenn der Prozessname mit einem Kleinbuchstaben beginnt, wird der Dienst in einem globalen Prozess mit diesem Namen ausgeführt, sofern er dazu berechtigt ist. Dadurch können Komponenten in verschiedenen Anwendungen einen Prozess gemeinsam nutzen, wodurch der Ressourcenverbrauch reduziert wird.

Bound Service mit Hilfe von Binder erstellen

Erstellen Sie eine Klasse, die die Service Klasse erweitert und in der überschriebenen Methode onBind Ihre lokale onBind zurückgeben:

public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods
            return LocalService.this;
        }
    }

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

Dann binden Sie in Ihrer Aktivität an den Service in onStart callback, verwenden die ServiceConnection Instanz und binden die Bindung von ihr in onStop

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // Bind to LocalService
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from the service
        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }

    /** Defines callbacks for service binding, passed to bindService() */
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

Remote-Service erstellen (über AIDL)

Beschreiben Sie Ihre Service-Zugriffsschnittstelle über die .aidl Datei:

// IRemoteService.aidl
package com.example.android;

// Declare any non-default types here with import statements

/** Example service interface */
interface IRemoteService {
    /** Request the process ID of this service, to do evil things with it. */
    int getPid();
}

Nach dem Erstellen der Anwendung generieren die sdk-Tools die entsprechende .java Datei. Diese Datei enthält die Stub Klasse, die unsere Hilfsschnittstelle implementiert und die wir erweitern müssen:

public class RemoteService extends Service {

    private final IRemoteService.Stub binder = new IRemoteService.Stub() {
        @Override
        public int getPid() throws RemoteException {
            return Process.myPid();
        }
    };

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

Dann in Tätigkeit:

public class MainActivity extends AppCompatActivity {
    private final ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            IRemoteService service = IRemoteService.Stub.asInterface(iBinder);
            Toast.makeText(this, "Activity process: " + Process.myPid + ", Service process: " + getRemotePid(service), LENGTH_SHORT).show();
        }

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, RemoteService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unbindService(connection);
    }

    private int getRemotePid(IRemoteService service) {
        int result = -1;

        try {
            result = service.getPid();
        } catch (RemoteException e) {
            e.printStackTrace();
        }

        return result;
    }
}

Erstellen eines ungebundenen Dienstes

Als Erstes fügen Sie den Service zu AndroidManifest.xml im <application> -Tag hinzu:

<application ...>

    ...        

    <service
        android:name=".RecordingService"
        <!--"enabled" tag specifies Whether or not the service can be instantiated by the system — "true" -->
        <!--if it can be, and "false" if not. The default value is "true".-->
        android:enabled="true"
        <!--exported tag specifies Whether or not components of other applications can invoke the -->
        <!--service or interact with it — "true" if they can, and "false" if not. When the value-->
        <!--is "false", only components of the same application or applications with the same user -->
        <!--ID can start the service or bind to it.-->
        android:exported="false" />

</application>

Wenn Sie Ihre Serviceklasse in einem separaten Paket verwalten möchten (z. B. .AllServices.RecordingService), müssen Sie angeben, wo sich Ihr Service befindet. In diesem Fall werden wir Folgendes ändern:

android:name=".RecordingService"

zu

android:name=".AllServices.RecordingService"

oder am einfachsten ist es, den vollständigen Paketnamen anzugeben.

Dann erstellen wir die eigentliche Serviceklasse:

public class RecordingService extends Service {
    private int NOTIFICATION = 1; // Unique identifier for our notification

    public static boolean isRunning = false;
    public static RecordingService instance = null;


    private NotificationManager notificationManager = null;


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

    @Override
    public void onCreate(){
        instance = this;
        isRunning = true;

        notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId){
        // The PendingIntent to launch our activity if the user selects this notification
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);

        // Set the info for the views that show in the notification panel.
        Notification notification = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)        // the status icon
                .setTicker("Service running...")           // the status text
                .setWhen(System.currentTimeMillis())       // the time stamp
                .setContentTitle("My App")                 // the label of the entry
                .setContentText("Service running...")      // the content of the entry
                .setContentIntent(contentIntent)           // the intent to send when the entry is clicked
                .setOngoing(true)                          // make persistent (disable swipe-away)
                .build();

        // Start service in foreground mode
        startForeground(NOTIFICATION, notification);

        return START_STICKY;
    }


    @Override
    public void onDestroy(){
        isRunning = false;
        instance = null;

        notificationManager.cancel(NOTIFICATION); // Remove notification

        super.onDestroy();
    }


    public void doSomething(){
        Toast.makeText(getApplicationContext(), "Doing stuff from service...", Toast.LENGTH_SHORT).show();
    }

}

Dieser Dienst zeigt lediglich eine Benachrichtigung an, wenn er ausgeführt wird, und er kann Toasts anzeigen, wenn seine doSomething() -Methode aufgerufen wird.

Wie Sie feststellen werden, ist es als Singleton implementiert und verfolgt die eigene Instanz - aber ohne die übliche statische Singleton Factory-Methode, da Services von Natur aus Singletons sind und durch Absichten erstellt werden. Die Instanz ist nach außen nützlich, um den Dienst bei seiner Ausführung "in den Griff zu bekommen".

Zuletzt müssen wir den Dienst aus einer Aktivität heraus starten und stoppen:

public void startOrStopService(){
    if( RecordingService.isRunning ){
        // Stop service
        Intent intent = new Intent(this, RecordingService.class);
        stopService(intent);
    }
    else {
        // Start service
        Intent intent = new Intent(this, RecordingService.class);
        startService(intent);
    }
}

In diesem Beispiel wird der Dienst abhängig vom aktuellen Status auf dieselbe Weise gestartet und gestoppt.

Wir können auch die doSomething() -Methode aus unserer Aktivität aufrufen:

public void makeServiceDoSomething(){
    if( RecordingService.isRunning )
        RecordingService.instance.doSomething();
}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow