Ricerca…


introduzione

Un servizio viene eseguito in background per eseguire operazioni di lunga durata o per eseguire lavori per processi remoti. Un servizio non fornisce alcuna interfaccia utente che viene eseguita solo in background con l'input dell'utente. Ad esempio, un servizio può riprodurre musica in sottofondo mentre l'utente si trova in un'app diversa, oppure potrebbe scaricare dati da Internet senza bloccare l'interazione dell'utente con il dispositivo Android.

Osservazioni

Se non hai definito il tuo servizio nel tuo AndroidManifest.xml, riceverai una ServiceNotFoundException quando tenti di avviarlo.

Nota:

Per informazioni su IntentService , vedere qui: Esempio di IntentService

Avvio di un servizio

Avviare un servizio è molto semplice, basta chiamare startService con un intento, all'interno di un'attività:

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.

Ciclo di vita di un servizio

Il ciclo di vita dei servizi presenta le seguenti richiamate

  • onCreate() :

Eseguito quando il servizio viene creato per configurare le configurazioni iniziali che potrebbero essere necessarie. Questo metodo viene eseguito solo se il servizio non è già in esecuzione.

  • onStartCommand() :

Eseguito ogni volta che startService() viene invocato da un altro componente, come un'attività o un BroadcastReceiver. Quando si utilizza questo metodo, il servizio verrà eseguito finché non si chiama stopSelf() o stopService() . Si noti che indipendentemente da quante volte si chiama onStartCommand() , i metodi stopSelf() e stopService() devono essere richiamati una sola volta per arrestare il servizio.

  • onBind() :

Eseguito quando un componente chiama bindService() e restituisce un'istanza di IBInder, fornendo un canale di comunicazione al Servizio. Una chiamata a bindService() manterrà il servizio in esecuzione finché ci sono client ad esso associati.

  • onDestroy() :

Eseguito quando il servizio non è più in uso e consente lo smaltimento delle risorse assegnate.

È importante notare che durante il ciclo di vita di un servizio potrebbero essere richiamati altri callback come onConfigurationChanged() e onLowMemory()

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

inserisci la descrizione dell'immagine qui

Definire il processo di un servizio

Il campo android:process definisce il nome del processo in cui deve essere eseguito il servizio. Normalmente, tutti i componenti di un'applicazione vengono eseguiti nel processo predefinito creato per l'applicazione. Tuttavia, un componente può sovrascrivere il valore predefinito con il proprio attributo di processo, consentendo di distribuire l'applicazione su più processi.

Se il nome assegnato a questo attributo inizia con due punti (':'), il servizio verrà eseguito nel suo processo separato.

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

Se il nome del processo inizia con un carattere minuscolo, il servizio verrà eseguito in un processo globale con quel nome, a condizione che abbia il permesso di farlo. Ciò consente ai componenti di diverse applicazioni di condividere un processo, riducendo l'utilizzo delle risorse.

Creazione del servizio associato con l'aiuto di Binder

Crea una classe che estende la classe di Service e in metodo sovrascritto onBind restituisce l'istanza di binder locale:

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

Quindi, durante l'attività, onStart binding al servizio in callback di onStart , utilizzando l'istanza ServiceConnection e separandoti da esso 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;
        }
    };
}

Creazione di un servizio remoto (tramite AIDL)

Descrivi la tua interfaccia di accesso al servizio tramite il file .aidl :

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

Ora dopo l'applicazione di build, gli strumenti sdk .java file .java appropriato. Questo file conterrà la classe Stub che implementa la nostra interfaccia aidl e che dobbiamo estendere:

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

Quindi in attività:

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

Creazione di un servizio non associato

La prima cosa da fare è aggiungere il servizio a AndroidManifest.xml , all'interno del tag <application> :

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

Se si intende gestire la classe di servizio in un pacchetto separato (ad esempio:. AllServices.RecordingService), sarà necessario specificare dove si trova il servizio. Quindi, nel caso di cui sopra modificheremo:

android:name=".RecordingService"

a

android:name=".AllServices.RecordingService"

o il modo più semplice per farlo è specificare il nome completo del pacchetto.

Quindi creiamo la classe di servizio effettiva:

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

}

Tutto questo servizio viene visualizzato quando è in esecuzione e può visualizzare toasts quando viene chiamato il metodo doSomething() .

Come si noterà, è implementato come un singleton , tenendo traccia della propria istanza, ma senza il solito metodo statico di fabbrica singleton perché i servizi sono naturalmente singleton e sono creati da intenti. L'istanza è utile all'esterno per ottenere un "handle" per il servizio quando è in esecuzione.

Infine, dobbiamo avviare e interrompere il servizio da un'attività:

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 questo esempio, il servizio viene avviato e interrotto con lo stesso metodo, a seconda del suo stato corrente.

Possiamo anche invocare il metodo doSomething() dalla nostra attività:

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


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow