IntentService详解

简介: IntentService是什么?这篇文章是之前就写好的,一直没有整理出来,这几天有空正好整理发布一下。我们知道Service可以让我们在后台处理一些事情,但是Service实际上也是主线程,所以执行长耗时任务时依然会ANR,只不过ANR触发时间要比前台长。一般我们会在Service中开启一个子线程去完成耗时任务。而IntentService就是解决这个问题的,它是Service的一个抽象子类,需要实现onHandleIntent,代码在这个函数中执行。它与Service最大的不同就是默认开启一个子线程,而onHandleIntent就是在子线程中执行的。

IntentService是什么?


这篇文章是之前就写好的,一直没有整理出来,这几天有空正好整理发布一下。

我们知道Service可以让我们在后台处理一些事情,但是Service实际上也是主线程,所以执行长耗时任务时依然会ANR,只不过ANR触发时间要比前台长。一般我们会在Service中开启一个子线程去完成耗时任务。

而IntentService就是解决这个问题的,它是Service的一个抽象子类,需要实现onHandleIntent,代码在这个函数中执行。它与Service最大的不同就是默认开启一个子线程,而onHandleIntent就是在子线程中执行的。

所以IntentService就是一个自带子线程的Service。

那么它是如何实现的,我们通过它的源码来简单分析一下。


线程的创建


IntentService的源码其实不多,先来看看它的onCreate函数


@Override
public void onCreate() {
    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}
复制代码


在onCreate中会创建并启动一个HandlerThread。这个HandlerThread是Thread的一个子类,通过它的源码可以看到实际上就是默认绑定开启了looper,它的run函数如下:


@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}
复制代码


可以看到绑定并启动了一个looper,而它的其他函数则都与looper和handler的操作有关,这里不一一看了。

回到onCreate中,接下来的代码则是通过HandlerThread的looper创建了一个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);
    }
}
复制代码


可以看到在handleMessage中调用了onHandleIntent,这样函数中的代码就在这个HandlerThread的子线程中运行。

然后执行了stopSelf函数,这个函数是Service的,用于停止服务的,与context的stopService效果是一样的。

也就是说IntentService执行onHandleIntent后就会试图停止服务,但是这里还有一些逻辑,注意传參是msg.arg1,这个很重要,后面会再详谈。


线程运行


通过上面我们知道,IntentService创建时开启一个线程并启动一个looper,并且通过ServiceHandler来执行代码。但是想要执行onHandleIntent,一定需要sendMessage,那么在哪send的呢?

答案是在Service的start周期中,如下:


@Override
public void onStart(@Nullable Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}
复制代码


可以看到在onStart中组合了一个msg并send,这样就实现了服务一启动就自动执行onHandleIntent。 注意msg的arg1参数赋值是startId,结合上面所说的就是执行onHandleIntent后会执行stopSelf(startId)

上面我们说过stopSelf会试图停止服务,为什么是试图而不是一定,关键就是startId这里。

只有当stopSelf函数的startId与Service当前的startId相同,才会停止服务,主要是针对多次startService的情况。

当我们多次startService的时候,startId会自动递增,并且保存最后一个startId。

所以多次startServiceonHandleIntent会执行多次,因为前几次执行到stopSelf时startId不同,只有当最后一个执行完后才真正的停止服务。

但是注意,在onBind函数中并没有sendMessage,所以IntentService需要使用start的方式,bind的方式由于不会走onStart这个周期,所以onHandleIntent不会执行。


退出线程


在创建线程时默认开启了looper,looper其实就是一个死循环,所以这个线程会一直阻塞。那么IntentService如何退出这个线程?

上面我们知道最后通过stopSelf停止服务,但是还没有看到对线程的操作。但是当我们停止服务时,会执行onDestroy函数,来看看源码:


@Override
public void onDestroy() {
    mServiceLooper.quit();
}
复制代码


这里将looper退出了,这样线程循环结束了线程就退出了。所以IntentService停止线程就会退出,如果多次启动service,那么最后一个执行完才会退出线程,这样也保证了任务全部被执行。


总结


IntentService其实很简单,就是内部实现了一个使用Handler机制的子线程而已,但是它使用起来方便了很多。



目录
相关文章
|
Android开发
Android多线程之IntentService
IntentService继承自Service,所以IntentService也是四大组件之一,IntentService内部封装了HandlerThread线程 (只有一个线程) 来按顺序处理异步任务
|
消息中间件 Java Android开发
冷启动与热启动,AsyncTask,HandlerThread,IntentService,Service 保活,IntentService
冷启动与热启动,AsyncTask,HandlerThread,IntentService,Service 保活,IntentService
131 1
|
存储 Java 数据库
深入剖析Android四大组件(一)——Activity生命周期详解(二)
深入剖析Android四大组件(一)——Activity生命周期详解(二)
139 0
深入剖析Android四大组件(一)——Activity生命周期详解(二)
|
Android开发
深入剖析Android四大组件(一)——Activity生命周期详解(一)
深入剖析Android四大组件(一)——Activity生命周期详解(一)
514 0
深入剖析Android四大组件(一)——Activity生命周期详解(一)
|
Android开发
Android四大组件之一Activity生命周期的不同走向
Android四大组件之一Activity的生命周期,欢迎大家阅读
103 0
Android四大组件之一Activity生命周期的不同走向
|
XML Java Android开发
Activity生命周期详解
Activity是由Activity栈进管理,当来到一个新的Activity后,此Activity将被加入到Activity栈顶,之前的Activity位于此Activity底部。
200 0
Activity生命周期详解
|
Java Android开发
AsyncTask
http://developer.android.youdaxue.com/reference/android/os/AsyncTask.html public abstract class AsyncTask extends Object java.lang.Object android.os.AsyncTask<Params, Progress, Result>
149 0
IntentService源码分析
我们知道Service是运行在主线程的,主线程中不能进行耗时操作,否则会发生ANR。Service中的发生ANR的超时时间是20s。 有时候我们需要应用在后台默默做一些任务,例如上传文件等。如果我们采用Service,则需要我们自己手动开启新的线程。如果我们不想 自己开启线程怎么办,IntentService就出现了。
HandlerThread原理与应用
HandlerThread  在理解了Handler的原理之后,我们知道在一个子线程中创建一个Handler不能缺少了Looper.prepare()和Looper.loop()两个方法,具体的原因这里不再赘述,不熟悉原理的可以先看下另一篇文章Handler的原理解析. 本篇文章主要是讲解HandlerThread的使用的。
1205 0