一、Service是什么
相信做android开发的同学们都或多或少的接触过Service,作为Android的四大组件之一,service主要使用在处理后台任务(即不依赖于UI界面),或者去执行一个需要长期运行的任务,譬如说播放音乐,下载等都可以放在service中做。service相对于activity来说,最大了区别在于,它处于后台运行,没有UI界面,当然你也可以将他与Notification一起使用,将service从后台转到前台。
二、Service的生命周期
Service和Activity一样具有生命周期。首先我们来看看Service的使用方法。
//service需要在AndroidManifest.xml中注册
public class AidlService extends Service
{
public AidlService()
{
}
@Override
public IBinder onBind(Intent intent)
{
return null;
}
@Override
public void onCreate()
{
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy()
{
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent)
{
return super.onUnbind(intent);
}
}
在上述的代码中,我们发现了与Activity生命周期相似的函数。毫无疑问,这就是Service的生命周期。其实Service的生命周期函数没有Activity与Fragment那么多。由上面代码可知主要包括onCreate,onStartCommand,onBind,onUnbind,onDestroy。那么是不是每一次启动Service都会执行这几个周期函数呢?其实不是,这与如何启动service有关。
Context.startService()
startService的作用是启动一个service,启动后这个service与当前的调用者(Activity,BroadCast等)没有关联,调用者将不知道service的运行情况,即使当前调用者退出,service也可以一直运行下去,直到调用stopServiceS(),或者stopSelf()函数。内存不足,也将优先回收后台进程。这种情况下,生命周期的执行步骤是onCreate()–onStartCommand()–onDestroy()。但如果启动的这个Servicer已经存在了,那么将不会执行onCreate()函数,只会执行onStartCommand()。
Intent intent=new Intent(MainActivity.this,AidlService.class);
startService(intent);
Context.bindService()
bindService()如它的名字来说是将调用者与服务绑定在一起,当调用者退出时,绑定的Service也将跟着销毁。因为调用者与服务绑定在一块,因此调用者可以知道服务的运行情况,并且能够与Service进行通信。这时候生命周期的执行为onCreate()–onBind()–onUnbind–onDestroy()。如果service以及存在,上述生命周期都不会再执行。
而且bindService也可以进行跨进程的通信。通过AIDL远程调用另一个进程中的Service,并得到另一个Service中的的信息。
Intent intent=new Intent(MainActivity.this,AidlService.class);
//bindService()一共有三个参数,第一个为Intent,第二个是ServiceConnection,这个需要自己创建,重写他的onServiceConnected()方法和onServiceDisconnected()方法,在onServiceConnected()函数中将得到service中onBindi函数中返回的IBinder,通过这个来与Service进行通信。第三个参数为标志位。
bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
private ServiceConnection mServiceConnection=new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
}
@Override
public void onServiceDisconnected(ComponentName name)
{
}
};
注意:如果你先startService再bindService或者先bindService再startService。那么单独的调用stopService和unbindService都将不会将service销毁,只用两个同时调用才能够销毁service。
三、对Service的误解
很多时候有人会想,同样是用来执行后台任务,同样是用来执行耗时任务,那么Service与Thread是不是一样呢?什么时候选择Service,什么时候又选择Thread呢?其实Service与Thread没有关系,Service更像Activity,因为Service与Activity都是运行在主线程中的,而Thread是重新开启一个子线程。而且注意!!!在service中不能够执行耗时的操作,如果超过20秒,将会报ANR。看到ANR是不是很熟悉,没错在Activity中如果执行耗时任务也会出现ANR。因此在Service的使用时一般会结合Thread一起使用,这样只要service存在那么线程也将运行,而且service不受Activity的销毁的影响,保证了耗时任务执行成功。
四、IntentService的使用
如果每次使用Service都去新创建一个Thread执行耗时任务,这样难免有些愚蠢,并且Thread与Service的通信也需要自己来完成。Android为我们提供了一个叫IntentService的类。它继承了Service,并且在内部包含了Thread和Handler。用户可以直接使用这个类来完成耗时的操作。
如何使用IntentService
public class MyIntentService extends IntentService
{
public MyIntentService()
{
super("MyIntentService");
}
@Override
public void onCreate()
{
super.onCreate();
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId)
{
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy()
{
super.onDestroy();
}
@Override
protected void onHandleIntent(Intent intent)
{
//执行耗时操作,该方法运行在工作线程中,而不是在主线程中。
//执行网络操作等。
}
}
由上面代码可以看到比service多了一个 onHandleIntent()方法。这个方法就是用来执行耗时操作的地方。它不是运行在主线程中,所以不会造成ANR。值得注意的是IntentService在执行完onHandleIntent()函数中的代码后,intentService将自己销毁掉自己,不会像service一样需要手动结束,不会一直运行下去。
其实查看IntentService源码,你会发现里面也只是运用了Thread与Handler。
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
public void onCreate() {
super.onCreate();
//HandlerThread是一个Thread,在它的run方法中,声明了一个Looper。
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
//线程开启
thread.start();
//将service中的looper赋值给ServiceHandler,因此ServiceHandler在发出Message后,会在 HandlerThread的run方法中取出消息。而重写的ServiceHandler的handleMessage方法,将会得到执行。而且我们发现ServiceHandler的handleMessage中有一个 onHandleIntent((Intent)msg.obj);这便是需要我们在继承IntentService时重写的。
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
//发送Message后,将会在HandlerThread的run方法中取出。
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
如果不是很明白IntentService的工作方式,建议先了解一下Handler机制。
五、结语
service在android开发中十分重要,我对它的理解其实也停留在很粗浅的层面。希望读者有什么观点,或者文章有什么错误,欢迎指正。