Sök…


Introduktion

En tjänst körs i bakgrunden för att utföra långvariga operationer eller för att utföra arbete för fjärrprocesser. En tjänst tillhandahåller inget användargränssnitt, den körs endast i bakgrunden med användarens inmatning. Till exempel kan en tjänst spela musik i bakgrunden medan användaren är i en annan app, eller den kan hämta data från internet utan att blockera användarens interaktion med Android-enheten.

Anmärkningar

Om du inte har definierat din tjänst i din AndroidManifest.xml, får du en ServiceNotFoundException när du försöker starta den.

Notera:

För information om IntentService , se här: IntentService Exempel

Starta en tjänst

Att starta en tjänst är väldigt enkelt, ring bara startService med avsikt från en aktivitet:

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.

Livscykel för en tjänst

Tjänstens livscykel har följande återuppringningar

  • onCreate() :

Körs när tjänsten först skapas för att ställa in de initiala konfigurationer du kanske behöver. Den här metoden körs endast om tjänsten inte redan körs.

  • onStartCommand() :

Körs varje gång startService() åberopas av en annan komponent, som en aktivitet eller en BroadcastReceiver. När du använder den här metoden körs tjänsten tills du ringer stopSelf() eller stopService() . Observera att oavsett hur många gånger du ringer onStartCommand() , stopSelf() metoderna stopSelf() och stopService() endast åberopas en gång för att stoppa tjänsten.

  • onBind() :

Körs när en komponent ringer bindService() och returnerar en instans av IBInder, som tillhandahåller en kommunikationskanal till tjänsten. Ett samtal till bindService() kommer att hålla tjänsten igång så länge det är klienter bundna till den.

  • onDestroy() :

Körs när tjänsten inte längre används och gör det möjligt att disponera resurser som har tilldelats.

Det är viktigt att notera att under en livscykel för en tjänst kan andra återuppringningar aktiveras såsom onConfigurationChanged() och onLowMemory()

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

ange bildbeskrivning här

Definiera processen för en tjänst

android:process definierar namnet på processen där tjänsten ska köras. Normalt körs alla komponenter i en applikation i standardprocessen som skapats för applikationen. En komponent kan dock åsidosätta standardområdet med sitt eget processattribut, så att du kan sprida din applikation över flera processer.

Om namnet som tilldelats detta attribut börjar med en kolon (':') kommer tjänsten att köras i sin egen separata process.

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

Om processnamnet börjar med en liten bokstav kommer tjänsten att köras i en global process med det namnet, förutsatt att den har tillstånd att göra det. Detta gör att komponenter i olika applikationer kan dela en process, vilket minskar resursanvändningen.

Skapa Bound Service med hjälp av Binder

Skapa en klass som utvidgar Service och i åsidosatt metod på onBind tillbaka din lokala bindemedelsinstans:

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

I din aktivitet binder du dig sedan till service i onStart återuppringning, använder ServiceConnection instansen och lossar från den i 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;
        }
    };
}

Skapa fjärrtjänst (via AIDL)

Beskriv ditt gränssnitt för åtkomst till .aidl genom .aidl fil:

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

Nu efter build-applikation kommer sdk-verktyg att generera lämplig .java fil. Den här filen kommer att innehålla Stub klassen som implementerar vårt hjälpgränssnitt och som vi behöver utöka:

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

Sedan i aktivitet:

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

Skapa en obunden tjänst

Det första du ska göra är att lägga till tjänsten till AndroidManifest.xml , inuti <application> -taggen:

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

Om du tänker hantera din serviceklass i ett separat paket (t.ex.: .AllServices.RecordingService) måste du ange var din tjänst är belägen. Så i fallet ovan kommer vi att ändra:

android:name=".RecordingService"

till

android:name=".AllServices.RecordingService"

eller det enklaste sättet att göra det är att ange det fullständiga paketnamnet.

Sedan skapar vi den faktiska serviceklassen:

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

}

Allt den här tjänsten gör är att visa en avisering när den körs, och den kan visa rostat bröd när dess doSomething() -metod kallas.

Som du kommer att märka är det implementerat som en singleton och håller koll på sin egen instans - men utan den vanliga statiska singleton-fabriksmetoden eftersom tjänster naturligtvis är singletoner och skapas av avsikter. Instansen är användbar för utsidan för att få ett "handtag" till tjänsten när den körs.

Till sist måste vi starta och stoppa tjänsten från en aktivitet:

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

I det här exemplet startas och stoppas tjänsten med samma metod, beroende på dess nuvarande tillstånd.

Vi kan också åberopa doSomething() -metoden från vår aktivitet:

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


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow