美文网首页
HandlerThread与IntentService源码学习

HandlerThread与IntentService源码学习

作者: 大棋17 | 来源:发表于2019-05-15 16:46 被阅读0次

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

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

    HandlerThread简单使用

    //创建子线程Handler
    HandlerThread 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个比较重要的变量:</br>
            1、mPriority 线程优先级</br>
            2、mLooper 本线程的Looper</br>
            3、mHandler 自带的Handler变量</br>

    #HandlerThread.java
    public 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
    @Override
    public 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对象上。</br>

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

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

            总得来说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的循环机制。</br>

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

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

    #HandlerThread.java
    public 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.java
    public void quit() {
        mQueue.quit(false);
    }
    
    public void quitSafely() {
        mQueue.quit(true);
    }
    

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

    #MessageQueue.java
    void 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()</br>

            当调用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);
            }
        }
    }
    

    从这两个源码中看出:</br>

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

            HandlerThread#quitSafely()先获取当前手机开机时间 now,只清除when大于now的Message,即被延迟处理的Message。</br>
            而对于小于当前手机开机时间的Message,则进行保留。而那些Message本该在HandlerThread退出前被处理的,但被正在处理的Message“卡住”,还没来得及处理,被迫留在Message链表中。

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

    @NonNull
    public 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.java
    public 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
    @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;
    }
    

            启动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.java
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }
    

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

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }
    

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

    相关文章

      网友评论

          本文标题:HandlerThread与IntentService源码学习

          本文链接:https://www.haomeiwen.com/subject/uecmaqtx.html