Zoeken…


Invoering

Een service wordt op de achtergrond uitgevoerd om langlopende bewerkingen uit te voeren of om werkzaamheden voor externe processen uit te voeren. Een service biedt geen gebruikersinterface die alleen op de achtergrond met gebruikersinvoer wordt uitgevoerd. Een service kan bijvoorbeeld muziek op de achtergrond afspelen terwijl de gebruiker zich in een andere app bevindt, of het kan gegevens van internet downloaden zonder de interactie van de gebruiker met het Android-apparaat te blokkeren.

Opmerkingen

Als u uw service niet hebt gedefinieerd in uw AndroidManifest.xml, ontvangt u een ServiceNotFoundException wanneer u deze probeert te starten.

Notitie:

Voor informatie over IntentService , zie hier: IntentService-voorbeeld

Een service starten

Een service starten is heel eenvoudig, bel startService met een intentie vanuit een activiteit:

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.

Levenscyclus van een service

De serviceslevenscyclus heeft de volgende callbacks

  • onCreate() :

Wordt uitgevoerd wanneer de service voor het eerst wordt gemaakt om de eerste configuraties in te stellen die u mogelijk nodig hebt. Deze methode wordt alleen uitgevoerd als de service nog niet actief is.

  • onStartCommand() :

Elke keer uitgevoerd startService() wordt aangeroepen door een ander onderdeel, zoals een activiteit of een BroadcastReceiver. Wanneer u deze methode gebruikt, wordt de Service uitgevoerd totdat u stopSelf() of stopService() . Merk op dat, ongeacht hoe vaak onStartCommand() , de methoden stopSelf() en stopService() slechts eenmaal moeten worden aangeroepen om de service te stoppen.

  • onBind() :

Uitgevoerd wanneer een component bindService() en een exemplaar van IBInder retourneert, dat een communicatiekanaal naar de Service levert. Een aanroep van bindService() zorgt ervoor dat de service actief blijft zolang er clients aan zijn gebonden.

  • onDestroy() :

Uitgevoerd wanneer de service niet meer in gebruik is en de toegewezen middelen kunnen worden verwijderd.

Het is belangrijk op te merken dat tijdens de levenscyclus van een service andere callbacks kunnen worden aangeroepen, zoals onConfigurationChanged() en onLowMemory()

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

voer hier de afbeeldingsbeschrijving in

Het proces van een service definiëren

Het veld android:process definieert de naam van het proces waar de service moet worden uitgevoerd. Normaal gesproken worden alle componenten van een toepassing uitgevoerd in het standaardproces dat voor de toepassing is gemaakt. Een component kan de standaardinstelling echter overschrijven met een eigen proceskenmerk, zodat u uw toepassing over meerdere processen kunt spreiden.

Als de naam die is toegewezen aan dit kenmerk begint met een dubbele punt (':'), wordt de service uitgevoerd in een afzonderlijk proces.

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

Als de procesnaam met een kleine letter begint, wordt de service uitgevoerd in een globaal proces met die naam, op voorwaarde dat het toestemming heeft. Hierdoor kunnen componenten in verschillende applicaties een proces delen, waardoor het gebruik van bronnen wordt beperkt.

Bound Service creëren met behulp van Binder

Maak een klasse die Service uitbreidt en in overschreven methode onBind retourneer uw lokale onBind :

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

Vervolgens bindt u in uw activiteit aan service in onStart callback, met behulp van ServiceConnection instantie en onStop deze 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;
        }
    };
}

Service op afstand maken (via AIDL)

Beschrijf uw servicetoegangsinterface via .aidl bestand:

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

Na het bouwen van de applicatie zullen de SDK-tools het juiste .java bestand genereren. Dit bestand bevat de Stub klasse die onze aidl-interface implementeert en die we moeten uitbreiden:

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

Vervolgens in activiteit:

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

Een ongebonden service maken

Het eerste wat u moet doen, is de service toevoegen aan AndroidManifest.xml , binnen de 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>

Als u uw serviceklasse in een apart pakket wilt beheren (bijvoorbeeld: .AllServices.RecordingService), moet u opgeven waar uw service zich bevindt. Dus in het bovenstaande geval zullen we wijzigen:

android:name=".RecordingService"

naar

android:name=".AllServices.RecordingService"

of de eenvoudigste manier om dit te doen is om de volledige pakketnaam op te geven.

Vervolgens maken we de daadwerkelijke 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();
    }

}

Het enige dat deze service doet, is een melding weergeven wanneer deze wordt uitgevoerd en toasts weergeven wanneer de methode doSomething() wordt aangeroepen.

Zoals u zult merken, is het geïmplementeerd als een singleton , waarbij het zijn eigen instantie bijhoudt - maar zonder de gebruikelijke statische singleton-fabrieksmethode omdat services van nature singletons zijn en door intenties zijn gecreëerd. Het exemplaar is handig voor de buitenkant om een "handle" voor de service te krijgen wanneer deze wordt uitgevoerd.

Ten slotte moeten we de service starten en stoppen met een activiteit:

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 dit voorbeeld wordt de service op dezelfde manier gestart en gestopt, afhankelijk van de huidige status.

We kunnen ook de methode doSomething() gebruiken voor onze activiteit:

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


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow