Android开发文档翻译之-Services
Service是一种能长期在后台运行同时不需要与用户进行交互的应用组件。其他组件可以开启service,开启后service可以自行运行及时用户已经切换到其他的应用。此外,组件可以与service进行绑定来进行交互,及时是跨进程的交互(Android的IPC机制)。网络操作、播放音乐、执行文件IO操作或是与内容提供者进行交互,这些操作都可以通过service在后台进行。
Service的两种形式:
Started
通过调用startService(),你可以启动一个service。一旦被启动,service可以独立的运行在后台,即使启动的组件被销毁。通常,被启动的service用来执行一个单一的操作,并且没有返回值。例如,下载网络上的一个文件。当操作执行完毕后,service应当自行结束。
Bound
通过调用bindService(),你可以绑定一个service。一个被绑定的service一般会提供一个接口用来与组件进行交互、发送请求、获取结果、甚至进行进程间的交互(IPC)。被绑定的service的生命周期和其绑定的组件相同。尽管多个组件可以同时绑定一个service,但是但所有这些组件进行解绑后,service会被销毁。
虽然文档中一般会对两种形式的service分开介绍,但是你可以同时开启和绑定service。只需要同时覆写两个回调-onStartCommand和onBind即可。
无论是用哪种方式启动service(或是两者都用),你都可以使用Intent来操作service,就想操作Activity一样。然而,如果你不想让其他应用使用你的service,你可以在manifest文件中将service申明为私有的,具体请看Service在清单文件中的申明。
基础介绍
想要使用service,你需要继承Service类或其子类。你需要覆写一些回调方法同时在这些方法中进行一些关键操作。一下是一些较为重要的生命周期回调回调:
onStartCommand()
系统会在你调用了startService后调用该函数。一旦该方法执行,service会被启动并独立运行在后台。如果你实现了该方法,你必须在合适的时机调用stopSelf()或者stopService()来停止service。(如果你仅提供绑定接口,你可以不实现该方法)
onBind()
当有其他组件通过bindService()绑定service后,系统会调用onBind()函数。你需要在该方法中提供一个实现了IBinder接口的类供给client使用。该方法必须要覆写,如果你不希望你的service提供绑定功能,你可以直接返回null。
Android系统会在内存较低时强制停止service;如果service被绑定在一个拥有焦点的activity上时,其被kill的风险会降低;如果一个service被申明为前台service,那么它几乎不会被kill。否者的话,如果service被长时间开启,那么随着时间的推移,service在系统中的优先级就会越低,被kill的风险就会越高。如果你的service被启动了,那么你就应该考虑到其被系统kill的情况。如果系统kill了一个service,那么在资源宽松的情况下,系统会重启它(这个需要根据你在onStartCommand()的返回值决定重启的策略)。
Service在清单文件中的申明
和activity一样,你需要在清单文件中申明service。
...
...
在service节点中可以申明一些其他的属性。这些属性都是可选的。只有android:name这一属性是必须的——该属性用来描述一个唯一的service类名,你应该确保不去修改该类名。
为了确保你的应用的安全性,应该使用显式意图来启动或者绑定service,并且不在service中申明intent-filters。
此外,你可以通过设置android:exported属性为false来确保你的service仅可以在你自己的应用中被使用。这可以有效得阻止其他应用使用你的service,即使通过显式意图也不可以。
以启动方式创建service
可以通过startService()来启动service,你可以监听到onStartCommand()回调。
当一个service被启动后,它将拥有独立的生命周期并且独立的运行在后台,即使开启它的组件被销毁。这种情况下,你需要在合适的时机调用stopSelf()来结束它或者通过调用stopServie()来结束它。
调用startService()时传递的Intent会在onStartCommand()回调时接收到。
注意:service会默认运行在申明service的那个应用进程中,并且会运行在主线程中。所以如果你的service在执行一些密集或阻塞的操作,那么可能会造成ANR现象。为了避免这种情况,你需要开启一个新的线程。
一般来说,你可以通过继承IntentService类来加速你的开发。
继承IntentService类
由于大部分的service都不需要处理并发请求,因此你可以通过继承IntentService类来加速你的开发。
IntentService有以下特性:
1.创建了一个工作线程来执行由onStartCommand()中传递的intent,该线程是和主线程分离的。
2.创建了一个工作队列用来依次执行intent,因此你不需要考虑多线程问题。
3.当所有任务执行结束后会自动的调用stopSelf()。
4.提供了onBind()的默认实现(return null)
5.提供了onStartCommand()的默认实现,发送任务到任务队列中并且回调onHandleIntent()
上述这些特性使得你只需要实现onHandleIntent()就可以完成client端的任务(你还需要提供一个简单的构造函数)
以下是IntentService的一个实现:
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.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
}
}
对比一下,如果你继承自service要实现相同功能所需写的代码:
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.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
// 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();
}
}
是不是累觉不爱,果断IntentService好啊。
然而,如果你希望实现并发操作,即不等上一个