An Introduction About Android Service
Bài đăng này đã không được cập nhật trong 2 năm
A service is a component which runs in the background without direct interaction with the user. As the service has no user interface, it is not bound to the lifecycle of an activity. Services are used for repetitive and potentially long running operations, i.e., Internet downloads, checking for new data, data processing, updating content providers and the like.Services run with a higher priority than inactive or invisible activities and therefore it is less likely that the Android system terminates them. Services can also be configured to be restarted if they get terminated by the Android system once sufficient system resources are available again.
Two important things everyone should remember to avoid any confusion about service :
-
A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
-
A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
Two main features of service are :
-
A facility for the application to tell the system about something it wants to be doing in the background (even when the user is not directly interacting with the application). This corresponds to calls to Context.startService(), which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it.
-
A facility for an application to expose some of its functionality to other applications. This corresponds to calls to Context.bindService(), which allows a long-standing connection to be made to the service in order to interact with it.
Service Lifecycle:
Started Service:
A Started Service is a Service that is explicitly started by either an object in the same application, or is started at device boot. There are two reasons that a service can be run by the system. If someone calls Context.startService() then the system will retrieve the service (creating it and calling its onCreate() method if needed) and then call its onStartCommand(Intent, int, int) method with the arguments supplied by the client. The service will at this point continue running until Context.stopService() or stopSelf() is called. Note that multiple calls to Context.startService() do not nest (though they do result in multiple corresponding calls to onStartCommand()), so no matter how many times it is started a service will be stopped once Context.stopService() or stopSelf() is called; however, services can use their stopSelf(int) method to ensure the service is not stopped until started intents have been processed.
For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand():
For example, the following code snippet shows an OnStartCommand implementation that returns StartResultCommand.Sticky, which will restart the Service automatically: @public override StartCommandResult OnStartCommand (Intent intent, StartCommandFlags flags, int startId)
{
// start a task here
new Task (() => {
// long running code
DoWork();
}).Start();
return StartCommandResult.Sticky;
}
Unless the task is started with the intention of running indefinitely, a Started Service should call StopSelf after any long-running work is done. This is important because the service runs independently of the component that called StartService, and will continue drawing on system resources until it is explicitly stopped or shut down by the OS. The following code calls the StopSelf method after it completes its work:
public void DoWork ()
{
new Task (() => {
Thread.Sleep (5000);
StopSelf ();
}).Start();
}
To avoid the possibility of a Service continuing indefinitely, the caller can also request that the Service be stopped by calling the StopService method, as shown below: StopService (new Intent (this, typeof(MyService))); When a Service is stopped, the OnDestroy method will be called on the Service. This is the part of the process where any cleanup of Service-wide resources should be done. To implement, simply override OnDestroy as follows:
public override void OnDestroy ()
{
base.OnDestroy ();
// cleanup code
}
Bound Service :
Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling onCreate() while doing so), but does not call onStartCommand(). The client will receive the IBinder object that the service returns from its onBind(Intent) method, allowing the client to then make calls back to the service. The service will remain running as long as the connection is established (whether or not the client retains a reference on the service's IBinder). A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service's onDestroy()method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers) should be complete upon returning from onDestroy(). The Service must override the OnBind method and return an IBinder object that contains a reference to the Service, e.g.:
public override IBinder OnBind (Intent intent)
{
binder = new MyServiceBinder (this);
return binder;
}
Hybrid Service:
The lifecycle of both Bound and Started Services can be combined by explicitly starting a Service and then binding to it. This offers the advantage of starting a Service independently of the rest of the application to provide it with an opportunity to do work, and then to also be able to connect to it directly in order to access it.
Service and Process:
The Android system will attempt to keep the process hosting a service around as long as the service has been started or has clients bound to it. When running low on memory and needing to kill existing processes, the priority of a process hosting the service will be the higher of the following possibilities:
-
If the service is currently executing code in its onCreate(), onStartCommand(), or onDestroy() methods, then the hosting process will be a foreground process to ensure this code can execute without being killed.
-
If the service has been started, then its hosting process is considered to be less important than any processes that are currently visible to the user on-screen, but more important than any process not visible. Because only a few processes are generally visible to the user, this means that the service should not be killed except in low memory conditions.
-
If the system considers a service to be something the user is actively aware of and thus not a candidate for killing when low on memory then a started service can use the startForeground(int, Notification) API to put the service in a foreground state
-
If there are clients bound to the service, then the service's hosting process is never less important than the most important client. That is, if one of its clients is visible to the user, then the service itself is considered to be visible. The way a client's importance impacts the service's importance can be adjusted through BIND_ABOVE_CLIENT, BIND_ALLOW_OOM_MANAGEMENT, BIND_WAIVE_PRIORITY, BIND_IMPORTANT, and BIND_ADJUST_WITH_ACTIVITY.
Note this means that most of the time your service is running, it may be killed by the system if it is under heavy memory pressure. If this happens, the system will later try to restart the service. An important consequence of this is that if you implement onStartCommand() to schedule work to be done asynchronously or in another thread, then you may want to use START_FLAG_REDELIVERY to have the system re-deliver an Intent for you so that it does not get lost if your service is killed while processing it. Other application components running in the same process as the service (such as an Activity) can, of course, increase the importance of the overall process beyond just the importance of the service itself.
Predefined system services and Custom Services:
The Android platform provides and runs predefined system services and every Android application can use them, given the right permissions. These system services are usually exposed via a specific Manager class. Access to them can be gained via the getSystemService() method. The Context class defines several constants for accessing these services. Custom services are started from other Android components, i.e., activities, broadcast receivers and other services. Custom service needs to be declared in the AndroidManifest.xml file and the implementing class must extend the Service class or one of its subclasses. The following code shows an example for a service declaration and its implementation.
<service
android:name="MyService"
android:icon="@drawable/icon"
android:label="@string/service_name"
>
</service>
public class MyService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO do something useful
return Service.START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
//TODO for communication return IBinder implementation
return null;
}
Running a Service in the Foreground:
A foreground service is a service that's considered to be something the user is actively aware of and thus not a candidate for the system to kill when low on memory. A foreground service must provide a notification for the status bar, which is placed under the "Ongoing" heading, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
Communication with services:
There are two ways to communicate with service
Intent data:
The service receives the intent data from the starting Android component and performs its work. No notification is necessary. For example, in case the service updates a content provider, the activity is notified by the content provider and no extra step in the service is necessary. This approach works for local and services running in their own process.
Broadcast Receiver:
You can also use broadcast events and registered receivers for the communication. For example,your activity can dynamically register a broadcast receiver for an event and the service sends outs corresponding events. This is a very typical scenario, in which the service need to signal to the activity that his processing has finished.
This communication flow is depicted in the following graphic.
In this walkthrough, we learned about different type of services, how to start them and communicate between service and activity.
All rights reserved