HanderThread源码分析

本文解析了Android中HandlerThread的工作原理,包括其构造方法、start()方法、run()方法及getLooper()方法的实现细节,帮助读者理解如何利用HandlerThread在子线程中处理消息。

前言

在读这篇文章之前最好先读一下我之前写的关于Handler原理的文章:Android Handler消息源码分析,这样会比较容易理解handlerThread的原理。

内容

HandlerThread相信很多人都已经用过,还不了解或者没有用过的同学请自行搜索。

先贴一下sample code

   HandlerThread handlerThread = new HandlerThread("sample");
   handlerThread.start();
   Handler handler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
       @Override
       public boolean handleMessage(Message msg) {
           Log.v("test","handleMessage");
           return false;
       }
   });
   for(int i=0;i<10;i++){
       try {
           Thread.sleep(1000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       handler.sendMessage(Message.obtain());
   }

废话不多讲,直接看HandlerThread的构造方法

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

因为HandlerThread类是继承自Thread类,所以先调用父类的方法,将Thread Name赋值,接着设置线程优先级。
接着在sample code中会调用start()方法,我们知道这个会让线程开始运行,并调用run()方法,所以我们直接看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.prepare(),初始化Looper对象,并给mLooper赋值。我们知道Looper.prepare()方法在哪个线程调用,这个Looper就属于哪个线程,所以在这里这个Looper就属于HandlerThread这个子线程。接着加一个锁,给mLooper赋值,然后通知等待线程。这段代码是对应于后面的另一个getLooper()方法,然后调用onLooperPrepared(),这个是空方法,子类在继承HandlerThread的时候可以重写这个方法,这样可以在消息循环真正跑起来之前做一些准备工作,然后再调用Looper.loop(),让消息循环真正跑起来。

我们继续看sample code,

  Handler handler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
      @Override
      public boolean handleMessage(Message msg) {
          Log.v("test","handleMessage");
          return false;
      }
  });

就是初始化一个Handler对象,将handlerThread的Looper作为参数专递给handler,这样做的作用是handler之后发送的消息就会送到这个handlerThread的子线程,而不是我们通常在使用的MainThread即UI线程。我们这里重点看一下handlerThread.getLooper()方法。

    /**
     * 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;
    }

从方法注释我们知道,只有当线程是live状态的时候才可以返回值,否则就返回null,这里面也有一个锁,大致逻辑就是如果发现mLooper是null则等待,直到被唤醒,那谁会唤醒它呢?从前面的分析知道,这个mLooper是在run方法里被赋值,也是在run方法里被赋值后唤醒getLooper方法中的锁,这个就实现了只要调用getLooper方法,就可以获得子线程looper的目的。

接下来就是用handler调用SendMessage给handlerThread发送消息了,这个中间的原理在之前的:Android Handler消息源码分析已经讲过,这里不再重复。最后调用handlerThread.quitSafely()方法退出HandlerThread的消息循环

    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

逻辑就是安全的退出消息循环,然后从run()方法返回,线程结束。handler还有另外一个退出方法就是quit(),这两个方法的区别是,quitSafely()在退出线程之前会分发完消息队列中剩下的message,但有个例外,就是通过postDelay方法发送的延迟消息也不会被分发,,而quit是直接退出,不管消息队列中还有没有消息,至于选择哪个方法,就看具体使用场景了。好了,就讲到这里,是不是很简单。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值