IntentService解析
看其结构:
public abstract class IntentService extends Service{...}
抽象类,该类继承自Service,子类需要实现的抽象方法为:
protected abstract void onHandleIntent(Intent intent);
对该方法,有两个问题:
- 该方法在源码哪里被调用
- 参数是什么
通过搜索IntentService类在该类内部实现了一个内部类ServiceHandler
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); } }
该类继承自Handler
,并在hanldeMessage(Message msg)
方法中调用onHandleIntent(Intent intent)
并通过stopSelf(int startId)
方法终止该Service。
经过测试,在调用
stopSelf(int startId)
去终结最近一个启动的Service时将会将Service销毁(调用到onDestroy()方法)。startId
从1开始逐一增长,最大的ServiceId代表最近被start的service。以下为测试代码和Log结果:
@Override public int onStartCommand(Intent intent, int flags, final int startId) { Log.e(TAG,"onStartCommand"); Log.e(TAG,"intent:"+intent+" ,flags:"+flags+" ,startId:"+startId); //测试stopSelf(int starId)是否能停止特定的startId对应的Service //结果:能,但是当停止最近启动的ServiceId时将会销毁整个Service new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(5000); Log.e(TAG,"启动的startId为:"+startId); stopSelf(2); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); return super.onStartCommand(intent, flags, startId); }
也就是说IntentService在处理完onHanldeIntent()
方法之后就销毁了。我看网上很多文章都说多次启动IntentService不会创建新的服务和新的线程,而实际上这是错误的理解。因为每次在调用完onHanleIntent方法之后该Service就已经被销毁,多次启动将会多次调用Service的onCreate方法去重新初始化Service。那就意味着我们在处理多任务时需要在onHandleIntent()
方法中自定义队列或者循环去发送事件。
那么以上我们了解了处理事件的方法onHandleIntent(Intent intent)
是在handler类中进行调用,那么发送这个Message的handler绑定了哪个线程,又是在哪里进行发送的呢?
我们找到ServiceHandler的对象mServiceHandler
,可以看到它是在Service类中的onCreate方法中进行初始化:
@Override public void onCreate() { // TODO: It would be nice to have an option to hold a partial wakelock // during processing, and to have a static startService(Context, Intent) // method that would launch the service & hand off a wakelock. super.onCreate(); //初始化HandlerThread并启动该线程 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); //初始化mServiceHandler mServiceHandler = new ServiceHandler(mServiceLooper); }
在HandlerThread中初始化了该Thread对应的Looper,mServiceHandler对象通过该Looper绑定该HandlerThread作为工作线程将需要工作的内容发送到handleMessage()
方法中进行处理,这就是为什么说IntentService能够异步处理数据,且不需要在处理耗时任务时自定义线程去处理。
我们知道通过startService启动Service调用的生命周期是onCreate->onStartCommand->onDestroy,而发送工作内容的代码就是在IntentService的onStartCommand方法中调用onStart方法实现(现在onStart()方法已被标记为弃用):
@Override public int onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; }@Override public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }
很普通的通过hanlder发送消息的代码,将intent封装到message.obj中发送到Handler的实现类ServiceHandler中去处理。
由此我们可以看到,onHandleIntent(Intent intent)
方法中的intent参数就是onStartCommand中的Intent参数,也就是我们通过starService启动的Intent参数,而每次我们通过startService方法启动IntentService实现类就和启动普通的Service类一样,调用到onStartCommand生命周期方法,然后在该方法中通过handler发送Intent到handleMessage方法中进行处理,最后在handleMessage()方法中调用抽象方法onHandleIntent(Intent intent)方法,该方法在IntentService类中暴露给用户去实现。
观察到IntentService在销毁Service时调用了Looper.quit()方法。
@Override public void onDestroy() { mServiceLooper.quit(); }
很好地实现了对Looper生命周期的设计,很多时候我们会忘记这些细节,而HandlerThread中绑定并启动Looper的代码在HandlerThread的run()方法中实现,一个标准的启动Looper代码:
@Override public void run() { mTid = Process.myTid(); //初始化Looper对象,初始化MessageQueue对象,关联当前线程 Looper.prepare(); synchronized (this) { //获取当前线程绑定的Looper mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); //HandlerThread类中留给子类去实现的空方法,目的是为了让子类做一些在Looper开始loop前的工作 onLooperPrepared(); //开启loop无限循环作业,处理MessageQueue中存储的的message Looper.loop(); mTid = -1; }
更多相关文章
- 使用Android(安卓)Camera2 API获取YUV数据
- sqlite 中判断某个表是否存在的方法
- android 调用视图报错The specified child already has a parent
- Android导入项目出现“R cannot be resolved to a variable"错误
- Android(安卓)相对布局中的 代码中修改属性与布局文件的设置不同
- Android学习笔记(二)——Android的数据存储(一)SharedPreferences
- Android(安卓)WebView 踩过的坑
- Fragment使用
- Android(安卓)N 各种ANR的时间