博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HandlerThread与IntentService源码剖析
阅读量:6412 次
发布时间:2019-06-23

本文共 8330 字,大约阅读时间需要 27 分钟。

Handler系列文章:

        

        HandlerThread是什么?HandlerThread的官方定义是:用于启动具有looper的新线程的方便类。然后可以使用looper来创建Handler类。

        简而言之就是:HandlerThread是一个启动好Looper的Thread对象,方便将Handler绑定在该线程中。

HandlerThread简单使用

//创建子线程HandlerHandlerThread mHandlerThread = new HandlerThread("daqi");mHandlerThread.start();Handler mHandler = new Handler(mHandlerThread.getLooper());mHandler.post(new Runnable() {    @Override    public void run() {    }});复制代码

HandlerThread源码分析

HandlerThread实际继承自Thread,实际也是一个Thread对象。

其中存在3个比较重要的变量:

        1、mPriority 线程优先级
        2、mLooper 本线程的Looper
        3、mHandler 自带的Handler变量

#HandlerThread.javapublic class HandlerThread extends Thread {    int mTid = -1;    //线程优先级    int mPriority;    //HandlerThread的Looper对象    Looper mLooper;    //自带的Handler    private @Nullable Handler mHandler;        public HandlerThread(String name) {        super(name);        //使用默认优先级        mPriority = Process.THREAD_PRIORITY_DEFAULT;    }        public HandlerThread(String name, int priority) {        super(name);        mPriority = priority;    }}复制代码

        当不指定线程优先级创建HandlerThread时,使用默认优先级初始化线程。

Thread对象最关键的就是run(),先从run方法看起:

HandlerThread.java@Overridepublic void run() {    mTid = Process.myTid();    //初始化Looper对象    Looper.prepare();    //加锁    synchronized (this) {        //获取该Thread的Looper对象        mLooper = Looper.myLooper();        //getLooper()再解析        notifyAll();    }    //设置该线程的优先级    Process.setThreadPriority(mPriority);    //Looper初始化完毕回调方法,用户可在这里初始化Handler    onLooperPrepared();    //启动Looper循环器    Looper.loop();    mTid = -1;}复制代码

        先初始化本线程的Looper对象,并赋值到mLooper对象上。

        再回调onLooperPrepared(),用户可重写该方法,在该方法中进行初始化Handler的操作。

        最后才调用Looper#loop()启动Looper的循环获取Message机制。

        总得来说HandlerThread#run()中进行了Looper初始化和Looper初始化完毕回调。

经常使用HandlerThread#getLooper()在初始化Handler时指定Handler所在的线程。查看getLooper()源码:

public Looper getLooper() {    //isAlive()检测线程是否还存活    if (!isAlive()) {        return null;    }        //加锁    synchronized (this) {        //当mLooper不为空时,才会返回mLooper        while (isAlive() && mLooper == null) {            try {                //等待                wait();            } catch (InterruptedException e) {            }        }    }    return mLooper;}复制代码

        当Looper没被初始化完毕时,调用getLooper()的线程会被挂起,等待Looper初始化完毕调用notifyAll()将其唤醒。

        当HandlerThread不再使用时,需要调用quit()或quitSafely()退出Looper的循环机制。

        因为run方法最后调用Looper#loop(),启动循环获取Message机制,run方法被"卡"在Looper#loop()上。只要当Looper退出循环机制时,run方法才执行完毕,线程也就“完成任务”自我销毁。

那 quit() 或 quitSafely() 有什么区别呢?

#HandlerThread.javapublic boolean quit() {    Looper looper = getLooper();    if (looper != null) {        looper.quit();        return true;    }    return false;}public boolean quitSafely() {    Looper looper = getLooper();    if (looper != null) {        looper.quitSafely();        return true;    }    return false;}复制代码
#Looper.javapublic void quit() {    mQueue.quit(false);}public void quitSafely() {    mQueue.quit(true);}复制代码

区别就是调用MessageQueue#quit()方法时,传递的boolean值参数不一样。继续查看MessageQueue#quit()的源码:

#MessageQueue.javavoid quit(boolean safe) {    //...    synchronized (this) {        if (mQuitting) {            return;        }        //标记正在退出        mQuitting = true;        if (safe) {            removeAllFutureMessagesLocked();        } else {            removeAllMessagesLocked();        }        // We can assume mPtr != 0 because mQuitting was previously false.        nativeWake(mPtr);    }}复制代码

        当调用HandlerThread#quitSafely()时,最终调用MessageQueue#removeAllFutureMessagesLocked()

        当调用HandlerThread#quit()时,最终调用MessageQueue#removeAllMessagesLocked()

private void removeAllMessagesLocked() {    //获取链表表头    Message p = mMessages;    //直接将Message链表全部回收    while (p != null) {        Message n = p.next;        p.recycleUnchecked();        p = n;    }    //将链表头置空    mMessages = null;}private void removeAllFutureMessagesLocked() {    //获取当前手机开机时间    final long now = SystemClock.uptimeMillis();    //获取MessageQueue中的Message链表表头    Message p = mMessages;    if (p != null) {        //如果链表表头Message对象的‘执行时间’比现在小,即表明当前暂无需要执行的Message        if (p.when > now) {            //即走quit()的路线,全部清除链表中的Message            removeAllMessagesLocked();        } else {            //否则当前存在需要马上执行 但又未发送到目标Handler进行处理的Message。            Message n;            for (;;) {                n = p.next;                //找到链尾还没有找到比当前时间大,即表示当前Message链表中的全部Message都是在退出前发送的,或者说在退出之前需要执行,但现在还没执行的。                //同时也表示没有延迟执行的Message,无需要清理的Message,直接退出方法。                if (n == null) {                    return;                }                //当找到第一个不是马上执行的Message对象时,退出死循环。                if (n.when > now) {                    break;                }                p = n;            }            //此时for循环退出,说明找到比当前开机时间大,需要延迟执行的Message。            //p.when仍比now(即当前开机时间)小,p.next.when才是比now大的。            //将p.next置空,即p作为当前链表的链尾,后面延迟的Message不再在链表中。            p.next = null;            //死循环,直到到链尾            //不断回收when比当前开机时间大的Message。            do {                p = n;                n = p.next;                p.recycleUnchecked();            } while (n != null);        }    }}复制代码

从这两个源码中看出:

        HandlerThread#quit()会全部清空MessageQueue中Message链表。

        HandlerThread#quitSafely()先获取当前手机开机时间 now,只清除when大于now的Message,即被延迟处理的Message。

        而对于小于当前手机开机时间的Message,则进行保留。而那些Message本该在HandlerThread退出前被处理的,但被正在处理的Message“卡住”,还没来得及处理,被迫留在Message链表中。

HandlerThread中还有一个很少被使用的方法,返回一个绑定当前线程的Handler实例:

@NonNullpublic Handler getThreadHandler() {    if (mHandler == null) {        mHandler = new Handler(getLooper());    }    return mHandler;}复制代码

IntentService源码分析

        为什么HandlerThread要和IntentService一起讲?因为IntentService其内部使用的就是HandlerThread,一个活生生的HandlerThread”实战案例“。加之有刚才HandlerThread的源码基础,理解IntentService源码也事半功倍。

什么是IntentService?简单点说就是:自带工作线程的Service。

        IntentService是抽象类,需要继承实现onHandleIntent()方法。在方法中处理启动Service时传递的Intent对象。 IntentService也是Service的子类,遵从Service的生命周期。先从onCreate()方法看起:

#IntentService.javapublic abstract class IntentService extends Service {    //工作线程Looper    private volatile Looper mServiceLooper;    //绑定工作线程的Handler    private volatile ServiceHandler mServiceHandler;    //HandlerThread的名称    private String mName;    //    private boolean mRedelivery;        //定义一个内部Handler类    private final class ServiceHandler extends Handler {        public ServiceHandler(Looper looper) {            super(looper);        }        @Override        public void handleMessage(Message msg) {            //将Message中存储的Intent对象,回调onHandleIntent(),传递给用户处理。            onHandleIntent((Intent)msg.obj);            //尝试自我销毁            stopSelf(msg.arg1);        }    }    public IntentService(String name) {        super();        mName = name;    }        @Override    public void onCreate() {        super.onCreate();        //创建HandelrThread        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");        thread.start();        //存储工作线程的Looper        mServiceLooper = thread.getLooper();        //创建handler并将其绑定在工作线程中。        mServiceHandler = new ServiceHandler(mServiceLooper);    }}复制代码

        初始化IntentService时,会创建IntentService工作的子线程,将初始化其内部Handler,绑定在工作线程中。

#IntentService.java@Overridepublic void onStart(@Nullable Intent intent, int startId) {    Message msg = mServiceHandler.obtainMessage();    msg.arg1 = startId;    msg.obj = intent;    mServiceHandler.sendMessage(msg);}@Overridepublic int onStartCommand(@Nullable Intent intent, int flags, int startId) {    onStart(intent, startId);    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;}复制代码

        启动service时,只有第一次初始化时才会调用onCreate(),onStartCommand()和onStart()每次都被调用。onStartCommand会告诉系统如何重启服务,如判断是否异常终止后重新启动等。

        onStartCommand()中会调用onStart()。IntentService#onStart(Intent,int)中将Intent对象封装成Message对象,交由Handler进行发送。

        而内部的Handler对象在handleMessage()中,将Intent对象从Message中取出,回调onHandleIntent(),交由用户进行处理。

最后onStartCommand的返回存在两种情况:

        1、START_REDELIVER_INTENT:如果此Service的进程在启动时被终止(即返回onStartCommand(Intent,int,int)之后),则Service将会被安排重新启动,并且最后一次传递的Intent将再次通过onStartCommand(Intent,int,int)重新传递给Service。

        2、START_NOT_STICKY:如果在执行完onStartCommand后,服务被异常终止,系统不会自动重启该服务。

mRedelivery用来标识是否将最后一次的Intent重新传递一遍。可以通过setIntentRedelivery进行设置:

#IntentService.javapublic void setIntentRedelivery(boolean enabled) {    mRedelivery = enabled;}复制代码

        一般情况下,mRedelivery为默认值,即为false。所以onStartCommand()一般返回START_NOT_STICKY,即被杀死后,则不重新启动再传递一次最后的Intent对象。

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

        IntentService被销毁时,也会退出Looper,结束工作线程。

转载于:https://juejin.im/post/5cd3d421f265da039e200b29

你可能感兴趣的文章
JavaScript简介
查看>>
SQL Server附加数据库拒绝访问解决方法汇总
查看>>
SM2算法原理及实现
查看>>
RHCA教材翻译计划
查看>>
js-小括号在不同场合下的作用
查看>>
我的友情链接
查看>>
kvm中虚拟机的硬盘扩容
查看>>
Android (Launch Mode) 四种启动模式
查看>>
透视学理论(二)
查看>>
Dubbo/HSF在Service Mesh下的思考和方案
查看>>
Django form表单
查看>>
CTYL-9.14(tomcat端口与阿里云安全组,域名与tomcat配置,域名与反向代理)
查看>>
Java 多线程相关问题记录
查看>>
LNMP架构介绍、MySQL安装、PHP安装、 Nginx介绍
查看>>
简单的Spark+Mysql整合开发
查看>>
阿里java面试经验大汇总(附阿里职位需求)
查看>>
Python全套零基础视频教程+软件2018最新编程视频!
查看>>
内存管理之1:x86段式内存管理与保护模式
查看>>
20180925上课截图
查看>>
IO输入/输出流的简单总结
查看>>