Pel impacients, en resum un servei Android:
Un servei és un component d'una aplicació que realitza tasques de "llarga durada" en segon terme i que no disposa d'interfície d'usuari.
Per exemple, una aplicació pot executar un servei i aquest servei continuar executant-se encara que l'aplicació que ha executat el servei finalitzi.
Com es comuniquem amb els serveis si no tenen interfície gràfica? Es possible fer una operació bind que permeti realitzar operacions interprocess communication (IPC) amb els serveis.
Exemples de tasques que pot realitzar un servei.
Els serveis poden tenir dos formes:
IMPORTANT: TODO
És possible que un servei sigui dels dos tipus al mateix temps, implementant els següents mètodes:
onStartCommand() per controlar com s'inicia el servei
i
onBind() per controlar el binding.
Els components poden utilitzar el servei de la mateixa forma que les activitats poden cridar altres activitats: utilitzant Intents.
Un servei és simplement un component que s'executa en segon terme quan l'usuari està treballant amb altres aplicacions. Per exemple, si només ens interessa realitzar tasques llargues fora del UI thread però aquestes tasques només es realitzen mentrestant l'usuari està interactuant amb la nostra aplicació, aleshores no utilitzeu un servei.
Un exemple es executar música en segon terme quan esteu utilitzant una aplicació. Un exemple seria un joc amb música. En canvi si esteu fent una aplicació que reprodueixi música i els vostres usuaris volen escoltar aquesta música mentrestant treballen amb altres aplicacions, aleshores cal fer un servei.
IMPORTANT: Cal tenir en compte que els serveis també s'executen al fil d'execució principal si no dieu el contrari. Per tant, també sol ser necessari executar els serveis en fils d'execució independents o worker threads.
Igual que les activitat (o qualsevol altre component android) el serveis s'han de declarar al fitxer de manifest de la vostra app.
Vegeu un exemple:
<manifest ... > ... <application ... > <service android:name=".ExampleService" /> ... </application> </manifest>
Com podeu veure és fa dins de l'element XML application i s'utilitzar l'exemple service. L'únic atribut requerit és:
android:name
i especifica la el nom de la clase que implementa el servei.
IMPORTANT: Un cop es publica l'aplicació no es recomanable canviar el nom del servei ja que això pot provocar que aplicacions externes deixin de funcionar al utilitzant Intents.
Consulteu:
http://developer.android.com/guide/topics/manifest/service-element.html
Per a més detalls sobre els atributs vàlids possibles.
Si la idea és que el servei només es pugui utilitzar localment (és a dir, només per la vostra pròpia aplicació) no s'ha de registrar camp Intent Filter. També es pot indicar com a privat amb:
android:exported amb el valor false
Com les activitats, es poden executar Intent Filters que permetin que altres components puguin invocar el servei utilitzant implicit intents. D'aquest forma qualsevol aplicació del dispositiu pot executar el vostre servei si utilitza el mètode startService() i aquest coincideix amb els intent filters declarats.
Per crear una classe servei només cal crear un classe filla de la classe Service o qualsevol de les subclasses existents i aleshores sobreescriure els mètodes adients. Els més importants són:
Si un component inicia un servei cridant a startService() (que realment provoca una crida a onStartCommand()), aleshores el servei s'executa fins que s'atura amb stopSelf() o un altre component l'atura amb stopService().
Si un component executa bindService() per a crear un servei (aleshores onStartCommand() no es crida, aleshores el servei només s'executa mentre el component es mantingui lligat al servei. Un cop tots els clients es deslliguen del servei el servei és aturat.
El sistema operatiu Android forçarà l'aturada d'un servei només quan la memòria esta molt malmesa i només per a recuperar l'aplicació amb la que està interactuant l'usuari. Vegeu Cicla de vida dels procesos Android.
NOTA: Si la versió d'Android és 1.6 o inferior, cal implementar onStart(), en comptes de onStartCommand().
Un started service és un que s'executa amb startService(), que provoca una crida al mètode onStartCommand().
En aquest cas el servei té un cicle de vida independent i s'executa de forma indefinida en segon terme. El cicle de vida es controla amb el mètodes:
Tradicionalment hi ha dos classe que es poden utilitzar per crear el vostre propi servei:
La majoria de serveis no necessiten processar múltiples peticions al mateix temps (el que implica un escenari de programació concurrent i multi-threading que pot ser perillós sinó s'implementa en cura). Per això utilitzem [IntentService]].
IntentService realitza les següents tasques:
En resum només cal implementar el mètode:
onHandleIntent()
per fer la feina que indiqui el client (cal també però tenir en compte el constructor del servei).
Vegem un exemple:
public class HelloIntentService extends IntentService { /** * A constructor is required, and must call the super IntentService(String) * constructor with a name for the worker thread. */ public HelloIntentService() { super("HelloIntentService"); } /** * The IntentService calls this method from the default worker thread with * the intent that started the service. When this method returns, IntentService * stops the service, as appropriate. */ @Override protected void onHandleIntent(Intent intent) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } } }
Si es decideix sobrescriure algun altre mètode com onCreate(), onStartCommand(), o onDestroy(), cal assegurar-se de cridar al mètode del pare.
Vegem un exemple:
@Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent,flags,startId); }
NOTA: Interessant quan cal fer multi-threading.
As you saw in the previous section, using IntentService makes your implementation of a started service very simple. If, however, you require your service to perform multi-threading (instead of processing start requests through a work queue), then you can extend the Service class to handle each intent.
Vegem un exemple, que fa el mateix que el codi de l'apartat anterior (fixeu-vos que és molt més simple fer-ho amb l'apartat anterior):time.
public class HelloService extends Service { private Looper mServiceLooper; private ServiceHandler mServiceHandler; // Handler that receives messages from the thread private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // Normally we would do some work here, like download a file. // For our sample, we just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } // Stop the service using the startId, so that we don't stop // the service in the middle of handling another job stopSelf(msg.arg1); } } @Override public void onCreate() { // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's // main thread, which we don't want to block. We also make it // background priority so CPU-intensive work will not disrupt our UI. HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); // Get the HandlerThread's Looper and use it for our Handler mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); // For each start request, send a message to start a job and deliver the // start ID so we know which request we're stopping when we finish the job Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; mServiceHandler.sendMessage(msg); // If we get killed, after returning from here, restart return START_STICKY; } @Override public IBinder onBind(Intent intent) { // We don't provide binding, so return null return null; } @Override public void onDestroy() { Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); } }
Notice that the onStartCommand() method must return an integer. The integer is a value that describes how the system should continue the service in the event that the system kills it (as discussed above, the default implementation for IntentService handles this for you, though you are able to modify it). The return value from onStartCommand() must be one of the following constants: