简介
- 在Android应用的程序中,普通的Service中的代码是运行在主线程中的,如果想要在Service中做些耗时的操作,就很容易出现ANR的现象(大概是20秒),那么我们经常的做法就是,在onStartCommon方法中开启一个子线程然后内部执行耗时的操作,在执行完毕后如果需要自动停止服务需要在子线程的run方法中调用stopSelf()来停止服务。
- 虽说在Service中执行耗时的代码可以很容易的实现,但是Android提供的IntentService类可以很方便的解决了自己开启线程和手动停止服务的问题。接下来看看IntentService的使用步骤。
使用步骤
- IntentService是一个抽象类内部有一个抽象的方法 handleIntent(),继承至Service类.所以使用它需要继承它实现抽象方法。
public class MyIntentService extends IntentService { private static final String TAG = "MyIntentService"; public MyIntentService() { super("MyIntentService"); } @Override protected void onHandleIntent(Intent intent) { //在这里通过intent携带的数据,开进行任务的操作。 Log.d(TAG, "onHandleIntent: " + Thread.currentThread().getName()); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy: "); } }
- 然后调用StartService()启动异步后台服务类 IntentService。
startService.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, MyIntentService.class); startService(intent); } });
源码分析
- 服务启动的过程中,会去执行服务的生命周期方法,在开启服务的时候,有两种方式,分别为startService和bindService
- startService方式启动,生命周期方法执行的顺序是 onCreate(),onStartCommand() onStart() onDestroy(),按照生命周期执行顺序我们查看IntentService的源码
// onCreate方法的分析
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
//创建了一个Looper对象 & MessageQueue对象 调用了Looper.loop方法
thread.start();
// 获取到HandlerThread中创建好的Looper对象。
mServiceLooper = thread.getLooper();
//ServiceHandler extends Handler,绑定了HandlerThread中的Looper对象 ;那个线程调用了Looper中的loop方法,Handler的dispatchMessage方法就运行在那个线程中。
mServiceHandler = new ServiceHandler(mServiceLooper);
}
//onStartCommand()方法分析
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
// 调用了onStart方法
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
//onStart方法
public void onStart(@Nullable Intent intent, int startId) {
//在这里构造了一个消息对象
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
//将intent 包装到了Message的obj中,
msg.obj = intent;
//然后调用sendMessage()将消息插入到队列中。
//最终消息被取出然后被分发,最后调用了handleMessage()来处理这个消息
mServiceHandler.sendMessage(msg);
}
//ServiceHandler handleMessage方法的分析
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//SeriviceHandler 的handleMessage()方法中 将接受到的消息交给onHandleIntent来处理,onHandleIntent方法就是我们实现的方法,获取到Intent,处理任务。
onHandleIntent((Intent) msg.obj);
//执行完 结束服务
stopSelf(msg.arg1);
}
}
// onDestroy()方法的处理
@Override
public void onDestroy() {
//将消息队列中的所有消息给移除,包括处理中的和未处理的
mServiceLooper.quit();
}
总结说来就是,开启服务执行onCreate()方法,方法中创建好了一个子线程(HandlerThread),(子线程中创建好了一个Looper对象同时创建好了一个MessagqQueue消息队列,然后开启轮询消息队列。),内部创建好的Handler与子线程中的Looper对象绑定。onCreate只有在服务第一次创建的时候才会调用,之后每次调用都只会执行onStartCommand方法,在此方法中我们构建好了一个Message对象,并且将传递进来的Intent封装在Mesage,一起发送到消息队列中。经过轮询将消息分发到Handler的handleMessage中处理,此时获取到Message中携带的Intent传递给我们实现好的handleIntent方法中进行任务的处理,处理完毕自动调用StopSlef来结束服务。在onDestroy方法会把所有消息都给退出。
- 上文中我们分析了startService方法启动的服务,那bindService方式启动服务的分析如下(绑定服务,建立长期通信),bindService启动会执行 onCreate -> onBind -> onUnBind -> onDestroy方法。
//onCreate方法上文中已经分析
//onBind()
public IBinder onBind(Intent intent) {
//直接返回null了。那么不对会Mesage对象和发送消息到队列中,
//然后回调handleIntent方法了。
return null;
}
所以bindService方式启动服务,不会进行多线程的操作。
问题记录
简单描述一下IntentService
- IntentService是一个特殊的Service类,是实现了多线程处理异步请求的一个服务类,在handleIntent方法中进行耗时的操作,如果有多个耗时的操作任务,会按照顺序去一个一个的执行,执行完一个关闭一个。
在源码handleMessage方法中为什么执行完handleIntent方法会去调用带参数的stopSelf()
- 因为stopSelf()的执行会立刻将服务停止掉,而带参数的stopSelf(int startId)会在所有任务执行完毕后将服务给停止。通常情况下调用stopSelf(int satrtId)方法不会立刻去执行停止服务的操作,会去判断最近执行任务的次数是否和startId相等,如果相等就立刻执行停止服务的操作。