美文网首页
Android HandlerThread 解析

Android HandlerThread 解析

作者: dashingqi | 来源:发表于2019-05-14 23:17 被阅读0次

简介

  • 我们知道如果在子线程中创建Handler的话,需要准备一个Looper对象,并且开启消息的轮询,如下
    new Thread(new Runnable() {
             @Override
             public void run() {
                 Looper.prepare();
                 Handler handler = new Handler();
                 Looper.loop();
             }
         }).start();
    
  • 那么我们在再说说这个HandlerThread
    • HanderThread是继承至Thread,并且内部创建了一个Looper对象存储在当前线程的本地存储区中,然后调用了Looper中的loop方法。
    • 其实Android提供这个HandlerThread就是为了避免在子线程中创建Handler时去自己创建Looper对象。

HandlerThread基本用法

  //1. 创建一个HandlerThread,
  //其中name是一个标记,声明线程名字,因为HandlerThread直接继承至Thread
  HandlerThread mHandlerThread = new HandlerThread("name");
  //2. 开启ThreadHandler,调用start()最终会回调内部实现的run方法。
 mHandlerThread.start(); 

  //3. 在Ui线程中声明一个UI线程中的Handler
  Handler uiHandler = new Handler();
  
  //4. 声明一个工作线程的Handler, 重写handleMessage方法。
   Handler mWorkHandler = new Handler(mHandlerThread.getLooper()){
        handleMessage(Message msg){
        //此时这个handleMessage方法是运行在HandlerThread线程中的。(反正不是UI线程中的)
        
          // 6.  调用UI线程的Handler来更新UI
          uiHandler.post(new Runnable(){
                  run(){
                      //更新UI
                    }  
          })
        
      }
  }

  //5. 调用工作线程发送消息
    Message msg = Message.obtain();
    msg.what = 1;
    msg.obj = "Hello World";
    mWorkHandler.sendMessage(msg)

源码解析

HandlerThread的源码分析就按照用法的顺序来进行分析了

  • 创建HandlerThread 看它的构造方法
    public HandlerThread(String name) {
      //其中name是一个标记声明线程的名字
      super(name);
      //在这里指定线程的优先级 这里的优先级 是Process 而不是Java里面的Thread.
      mPriority = Process.THREAD_PRIORITY_DEFAULT;
      }
    /**
    * Constructs a HandlerThread.
    * @param name
    * @param priority The priority to run the thread at. The value supplied must be from 
    * {@link android.os.Process} and not from java.lang.Thread.
    */
    public HandlerThread(String name, int priority) {
      super(name);
      //我们可以自定义线程的优先级,默认是THREAD_PRIORITY_DEFAULT
      mPriority = priority;
    }
    
  • 调用start方法开启线程

因为HandlerThread继承Thread调用start最终会回调run所以我们看内部的run方法就行。

  • run()
    public void run() {
        // 获取到当前线程的ID
        mTid = Process.myTid();
        // 创建一个Looper & MeesageQueue对象。
        Looper.prepare();
        //通过持有锁的机制,来获取到Looper对象
        synchronized (this) {
            mLooper = Looper.myLooper();
            //发出通知,Looper对象已经创建成功了。
            //这里调用notifyAll是为了唤醒下文中getLooper的方法。
            notifyAll();
        }
        //设置当前线程的优先级
        Process.setThreadPriority(mPriority);
        
        //这是一个空方法,在执行线程之前进行初始化的操作,调用者可以重写该方法自行实现内部的方法。
        onLooperPrepared();
        //循环获取MessageQueue中的消息,并且将消息分发出去。
        Looper.loop();
        mTid = -1;
    }
    
  • getLooper()
    public Looper getLooper() {
         //如果当前线程没有存活,就返回null
       If (!isAlive()) {
           return null;
       }
    
       // If the thread has been started, wait until the looper has been created.
       //运用到锁机制
       synchronized (this) {
           //如果当前线程是存活状态 & mLooper对象并没有创建成功!
          //就阻塞线程
           while (isAlive() && mLooper == null) {
               try {
                
                 // run方法中的notifyAll就是为了通知wait方法,Looper对象创建成功了,这时就返回Looper对象了。
                // 因为工作Handler调用了 ThreadHandler中的getLooper()f方法,WorkHandler是创建在UI线程的,而ThreadHandler调用start()方法是运行在子线程中的,
               //当UI线程要获取Looper对象的时候,如果这时子线程并没有创建好Looper对象,那么这时就处于阻塞的状态,直到Looper对象创建成功,返回Looper对象。
                   wait();
               } catch (InterruptedException e) {
               }
           }
       }
       return mLooper;
    }
    
  • quit 和 quitSafely
      // quit()
      //在消息机制中分析过,Looper调用了quit最终是在MessageQueue中调用了,removeAllMessagesLocked()方法,
      //该方法是将消息队列中的所有消息退出,包括运行中的和没有运行的
        public boolean quit() {
          Looper looper = getLooper();
          if (looper != null) {
              looper.quit();
              return true;
          }
          return false;
      }
      //quiSafely
      // Looper调用了quitSafely()最终调用了MessageQueue中的removeAllFutureMessagesLocked()
      // 该方法是将消息队列中未运行的消息给 退出,运行中的九让它继续运行了。
      public boolean quitSafely() {
          Looper looper = getLooper();
          if (looper != null) {
              looper.quitSafely();
              return true;
          }
          return false;
      }
    

问题记录

  • HandlerThread中的run方法是一个无限循环,当确认ThreadHandler不在使用的情况下,调用quie或者quitSafely()来退出ThreadHandler线程中创建的MessageQueue

相关文章

网友评论

      本文标题:Android HandlerThread 解析

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