前言
IntentService
=Service
+ 多线程,其中涉及到Handler
队列请求,多线程Lopper
的使用,IntentService
的自动销毁
1. 演示示例
效果是连续点击一个按钮,触发startService
,将任务交给IntentService
处理;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//点击button触发
public void startService(View view) {
Log.d(TAG, "click button to start service");
Intent intent = new Intent(this, TestIntentService.class);
startService(intent);
}
}
//service 代码
public class TestIntentService extends IntentService {
private static final String TAG = "IntentService";
public TestIntentService() {
super("intent-service");
Log.d(TAG, "constructor");
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate");
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
Log.d(TAG, "onStart");
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent");
for (int i = 0; i < 8; i++) {
Log.d(TAG, "onHandleIntent ----"+Thread.currentThread().getName()+", i="+i);
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
}
- 多次频繁点击按钮,日志如下:
2019-05-22 11:13:41.793 5863-5863/com.linx.jnitest D/MainActivity: click button to start service
2019-05-22 11:13:41.876 5863-5863/com.linx.jnitest D/IntentService: constructor
2019-05-22 11:13:41.877 5863-5863/com.linx.jnitest D/IntentService: onCreate
2019-05-22 11:13:41.890 5863-5863/com.linx.jnitest D/IntentService: onStartCommand
2019-05-22 11:13:41.890 5863-5863/com.linx.jnitest D/IntentService: onStart
2019-05-22 11:13:41.891 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent
2019-05-22 11:13:41.891 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=0
2019-05-22 11:13:42.121 5863-5863/com.linx.jnitest D/MainActivity: click button to start service
2019-05-22 11:13:42.149 5863-5863/com.linx.jnitest D/IntentService: onStartCommand
2019-05-22 11:13:42.149 5863-5863/com.linx.jnitest D/IntentService: onStart
2019-05-22 11:13:42.484 5863-5863/com.linx.jnitest D/MainActivity: click button to start service
2019-05-22 11:13:42.489 5863-5863/com.linx.jnitest D/IntentService: onStartCommand
2019-05-22 11:13:42.490 5863-5863/com.linx.jnitest D/IntentService: onStart
2019-05-22 11:13:42.692 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=1
2019-05-22 11:13:43.493 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=2
2019-05-22 11:13:44.294 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=3
2019-05-22 11:13:45.095 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=4
2019-05-22 11:13:45.895 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=5
2019-05-22 11:13:46.696 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=6
2019-05-22 11:13:47.497 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=7
2019-05-22 11:13:48.300 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent
2019-05-22 11:13:48.300 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=0
2019-05-22 11:13:49.101 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=1
2019-05-22 11:13:49.901 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=2
2019-05-22 11:13:50.702 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=3
2019-05-22 11:13:51.503 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=4
2019-05-22 11:13:52.304 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=5
2019-05-22 11:13:53.104 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=6
2019-05-22 11:13:53.905 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=7
2019-05-22 11:13:54.708 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent
2019-05-22 11:13:54.708 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=0
2019-05-22 11:13:55.509 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=1
2019-05-22 11:13:56.310 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=2
2019-05-22 11:13:57.110 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=3
2019-05-22 11:13:57.911 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=4
2019-05-22 11:13:58.712 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=5
2019-05-22 11:13:59.513 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=6
2019-05-22 11:14:00.313 5863-6106/com.linx.jnitest D/IntentService: onHandleIntent ----IntentService[intent-service], i=7
2019-05-22 11:14:01.118 5863-5863/com.linx.jnitest D/IntentService: onDestroy
2. 分析结果
- constructor、
onCreate
仅走了一次,IntentService
和普通Service一样,多次start,仅仅创建一个实例,onCreate
生命周期仅走一次; - 多次start,都会重复走生命周期:
onStartCommand
–>onStart
–>onHandleIntent
onHandleIntent
中可以执行多线程操作,例如阻塞线程;这是与UI线程不可阻塞最大的区别;onHandleIntent
的任务是顺序执行的,当前一个任务执行完毕后才能执行下一个任务onHandleIntent
执行在工作线程,线程名称是IntentService[name]
,name是构造函数中传入的- 当所有任务执行完毕之后,
IntentService
自动onDestroy
,自动销毁本身,无需stop
3. 分析IntentService
源码
- 首先从构造函数看起:
构建了IntentService,name是用来给工作线程命名的,可以用来debug;很简单那么name哪里用到呢?/** * Creates an IntentService. Invoked by your subclass's constructor. * * @param name Used to name the worker thread, important only for debugging. */ public IntentService(String name) { super(); mName = name; }
IntentService
的两大组件:HandlerThread
和ServiceHandler
从这里可以看出,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 thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper() /*这里获取该子线程的Looper*/ mServiceHandler = new ServiceHandler(mServiceLooper); }
HandlerThread
和一个ServiceHandler
;name作为HandlerThread的[name]参数传入
ServiceHandler
使用了HandlerThread的looper,所以这个Handler创建后,会采用HandlerThread线程的Looper来构建内部消息循环系统,也就是说其handleMessage()
工作在子线程;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); } }
HandlerThread
继承自Thread,是一个线程,并且具备自己的looper,可以通过 getLooper() 获取;
这里可以看出,Looper是在run()方法中创建的,如果getLooper()为null时,就等待直到run方法创建了looper@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } /* * This method returns the Looper associated with this thread. If this thread not been started * or for any reason isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized. * @return The looper. */ public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; }
下面来看看onHandleIntent何时调用的:onHandleIntent
的调用:
这里可以看出@Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } /** * You should not override this method for your IntentService. Instead, * override {@link #onHandleIntent}, which the system calls when the IntentService * receives a start request. * @see android.app.Service#onStartCommand */ @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; }
onStartCommand
调用了onStart
,onStart
又发送了消息,消息中携带了startService
时传入的 intent;后续的任务都交给了handlMessage处理;handleMessage
的逻辑:
我们再来看一下ServiceHandler怎么处理消息的:
可以看出,首先将消息交给子线程处理,然后再结束掉该Service;那么onDestroy应该每次都执行,显然不对,那么为什么最后才onDestroy呢?@Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); }
再看stopSelf的源码:在Service.java中
这里/** * Old version of {@link #stopSelfResult} that doesn't return a result. * * @see #stopSelfResult */ public final void stopSelf(int startId) { if (mActivityManager == null) { return; } try { mActivityManager.stopServiceToken( new ComponentName(this, mClassName), mToken, startId); } catch (RemoteException ex) { } } /** * Stop the service if the most recent time it was started was * <var>startId</var>. This is the same as calling {@link * android.content.Context#stopService} for this particular service but allows you to * safely avoid stopping if there is a start request from a client that you * haven't yet seen in {@link #onStart}. * * <p><em>Be careful about ordering of your calls to this function.</em>. * If you call this function with the most-recently received ID before * you have called it for previously received IDs, the service will be * immediately stopped anyway. If you may end up processing IDs out * of order (such as by dispatching them on separate threads), then you * are responsible for stopping them in the same order you received them.</p> * * @param startId The most recent start identifier received in {@link * #onStart}. * @return Returns true if the startId matches the last start request * and the service will be stopped, else false. * * @see #stopSelf() */ public final boolean stopSelfResult(int startId) { if (mActivityManager == null) { return false; } try { return mActivityManager.stopServiceToken( new ComponentName(this, mClassName), mToken, startId); } catch (RemoteException ex) { } return false; }
stopSelf
与stopSelfResult
代码基本一致,只是返回值为void;通过注释可以看出,这个接口的每次调用不一定真的就销毁了该Service,只有当startId与最近一次startService的Id相同,才会stop这个服务。
参数startId:int,用来标识Service的启用号。每次startService()系统会自动为开启的Service产生一个不同的startId,之前赋予它的startId(如果有)将会被覆盖,并且这个新产生的startId会成为这个Service的新的startId,无论Service是否正在运行。说明一下,startId是AMS生成的,不可由应用层指定
因此当最后一次onHandleIntent
执行完毕后,会发现,这次的startId与最后一次的startId一致,因此才会成功的销毁这个服务;
总结
IntentService
是一个内置了工作线程的服务- 工作线程是单线程,且任务按照队列先入先出原则依次执行
- 工作线程执行完毕就会自动销毁服务,不必手动stop
IntentService
可以用来做可靠的耗时任务处理,例如网络下载、关键的异步任务等等,因为是由Service创建的线程,因此执行过程不会由于Activity的退出而降低优先级而被系统清理中断,因此很可靠