IntentService 深度解析(实例 + 源码)
上一篇:
上文说过Service默认工作在当前进程的主线程中,如需执行耗时操作,需要手动开启线程;且一旦开启服务,就会一直运行,直到stopService()或者stopSelf();也就是说我们在线程任务执行完毕后需要手动stopSelf(),才能释放service资源。
android提供了IntentService来实现这个功能,封装了线程,并能够在线程任务执行完毕后,结束service
IntentService的使用
模拟下载一个视频文件的功能:
1、AndroidManifest中注册
<service android:name=".update.UpdateService" />
2、自定义Service继承自IntentService
以下两个方法必须实现,其余是为了探讨IntentService的生命周期,可以自行去掉
- 实现空参构造方法UpdateService(),super(“xx”) //xx是定义的线程名
- onHandleIntent(),onHandleIntent是在子线程中运行的,可以直接执行耗时操作。
public class UpdateService extends IntentService {
//必须实现,指定线程名
public UpdateService() {
super("customThread");
Log.e("zhen", "UpdateService: customThread" );
}
@Override
public void onCreate() {
super.onCreate();
Log.e("zhen", "UpdateService: onCreate ");
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.e("zhen", "UpdateService: onStartCommand ");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("zhen", "UpdateService: onDestroy ");
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
super.onStart(intent, startId);
Log.e("zhen", "UpdateService: onStart ");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e("zhen", "UpdateService: onBind ");
return super.onBind(intent);
}
//必须实现,默认在子线程中操作
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.e("zhen", "UpdateService: onHandleIntent thread: " + Thread.currentThread().toString());
Log.e("zhen", "开始下载");
int i = 0;
try {
do {
Thread.sleep(2000);
i += 20;
Log.e("zhen", "下载进度: " + i + "% ...");
} while (i < 100);
Log.e("zhen", "下载完成!");
} catch (InterruptedException e) {
e.printStackTrace();
Log.e("zhen", "下载失败!");
}
}
}
3、启动service
Intent intent = new Intent(this, UpdateService.class)
startService(intent)
IntentService 生命周期
日志打印:
1、点击一次startService
构造函数 -> onCreate -> onStartCommand -> onStart -> onHandleIntent -> onDestroy
2、点击两次startService
-
在onDestroy之前会回调service的 onStartCommand -> onStart
-
在第一次任务的onHandleIntent执行完毕后,才开始执行第二次任务的onHandleIntent (顺序执行)
-
所有任务都执行完毕后才执行onDestroy
IntentService源码解析
startService()是由系统来启动service的
1、onCreate()
- 创建一个名为IntentService[xx]的handlerThread,并启动这个线程
- 得到这个线程所对应Looper,并根据Looper创建对应的ServiceHandler,来处理message
2、onStartCommand() - > onStart() -> serviceHanlder.sendMessage()
3、通过Looper调度 -> serviceHandler.handleMessage() -> onHandleIntent()(需要子类实现的抽象方法)
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
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 IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
现在可以解释一下多次点击startService的执行过程了
-
多次点击startService,onCreate只执行一次,但onStartCommand会回调多次,也就是说会通过serviceHandler发送多个message给serviceHandler;
-
根据Looper.loop(),循环从MessageQueue中取出消息,回调serviceHandler的handleMessage(),也就是说会依次按顺序执行onHandleIntent()
-
多次启动service不会重新创建新的服务和新的线程,只是把消息加入消息队列中等待执行,而如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。
解答疑惑:
1、为什么不通过bindService()来启动IntentService?
IntentService继承自Service,所以bindService()可以实现正常的service操作;但是上文我们说过通过bindService启动的service不会回调onStartCommand(),也就不会执行start() -> serviceHandler.sendMessage() -> serviceHandler.handleMessage(),这样启动的IntentService将毫无意义。
2、手动stopService怎么执行的?
执行到onDestroy() -> mServiceLooper.quit() -> mQueue.quit(false) -> removeAllMessagesLocked()
MessageQueue.java 循环遍历,清除所有消息
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
3、为什么每次onHanleIntent之后都会执行stopSelf(),为什么不会多次onDestroy() 呢?
因为stopSelf()会进行检查,只有等到所有任务都执行完成后才会真正的destroy
源码解释一波:
IntentService.java # stopSelf(msg.arg1)
//多次点击的startId是从1开始递增
Service.java # stopSelf(int startId)
ActivityManagerService.java # stopServiceToken(ComponentName className, IBinder token, int startId)
ActiveServices.java
boolean stopServiceTokenLocked(ComponentName className, IBinder token,
int startId) {
ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId());
if (r != null) {
if (startId >= 0) {
// Asked to only stop if done with all work. Note that
// to avoid leaks, we will take this as dropping all
// start items up to and including this one.
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
if (si != null) {
while (r.deliveredStarts.size() > 0) {
ServiceRecord.StartItem cur = r.deliveredStarts.remove(0);
cur.removeUriPermissionsLocked();
if (cur == si) {
break;
}
}
}
if (r.getLastStartId() != startId) {
return false; //就是这里啦。。。。。。
}
}
//省略部分代码
return true;
}
return false;
}