HandlerThread源码分析及使用

Android中Handler在使用时,一般都在UI主线程中执行,因此Handler在处理消息时,不能做一些很耗时的操作,否则将出现ANR错误。因此,Android中专门提供了HandlerThread类,来解决该类问题。

HandlerThread类源码在frameworks/base/core/java/android/os/HandlerThread.java文件中。

源码:

/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 */
public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        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);
        mPriority = priority;
    }
    
    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    
    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason is 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;
    }

    /**
     * Quits the handler thread's looper.
     * <p>
     * Causes the handler thread's looper to terminate without processing any
     * more messages in the message queue.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p class="note">
     * Using this method may be unsafe because some messages may not be delivered
     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
     * that all pending work is completed in an orderly manner.
     * </p>
     *
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     *
     * @see #quitSafely
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    /**
     * Quits the handler thread's looper safely.
     * <p>
     * Causes the handler thread's looper to terminate as soon as all remaining messages
     * in the message queue that are already due to be delivered have been handled.
     * Pending delayed messages with due times in the future will not be delivered.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p>
     * If the thread has not been started or has finished (that is if
     * {@link #getLooper} returns null), then false is returned.
     * Otherwise the looper is asked to quit and true is returned.
     * </p>
     *
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    /**
     * Returns the identifier of this thread. See Process.myTid().
     */
    public int getThreadId() {
        return mTid;
    }
}


HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它有个Looper成员变量。这个Looper其实就是对消息队列以及队列处理逻辑的封装,简单说就是 消息队列+消息循环。


在run()方法中创建该线程的Looper对象,并通过Looper.loop()开启持续访问MessageQueue消息队列的循环遍历操作(死循环,没有任务时阻塞,等待新Message的到来)。因此,HandlerThread所产生的线程会一直存在。

接着我们分析getLooper()方法,首先判断该线程是否是活动状态,若该线程还未开启或已结束运行则返回null,若该线程已经开启但Looper还未创建,则等待直到Looper创建,然后返回该Looper。

接着看quit()方法,该方法首先获取当前线程的Looper,然后调用looper.quit()结束当前的消息循环操作,退出Looper.loop()操作,从而退出当前线程。


HandlerThread类是一个线程,专门处理Hanlder的消息,依次从Handler的队列中获取信息,逐个进行处理,保证安全,不会出现混乱引发的异常。
有时候我们需要在应用程序中创建一些常驻的子线程来不定期地执行一些计算型任务,这时候就可以考虑使用Android系统提供的HandlerThread类了,它具有创建具有消息循环功能的子线程的作用。
当我们需要一个工作线程,而不是把它当作一次性消耗品(用过即废弃的话),就可以使用它。
下面举例说明HandlerThread如何使用:
public class HandlerThreadActivity extends Activity {
    private static final String TAG = "HandlerThreadActivity";
    private HandlerThread mHandlerThread;
    private MyHandler mMyHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main_activity);
      
       Log.d(TAG, "mainthread id : " + Thread.currentThread().getId());
      
       //生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能
       mHandlerThread = new HandlerThread("handler_thread");
      
       // mHandlerThread.setPriority(Thread.MIN_PRIORITY); // 给工作者线程低优先级 
       //在使用HandlerThread的getLooper()方法之前,必须先调用该类的start();
       mHandlerThread.start();
       //即这个Handler是运行在mHandlerThread这个线程中
       mMyHandler = new MyHandler(mHandlerThread.getLooper());
      
       mMyHandler.sendEmptyMessage(1);

       //也可使用handler的post方法(实现Runnable类的run方法)实现具体的处理,
       //从而可以不实现Handler的子类(即MyHandler)及其handleMessage方法,
       //则 mMyHandler = new Handler(mHandlerThread.getLooper());
       mMyHandler.post(new Runnable({
                @Override
                public void run() {
                    ......
                }
            }));
    }
   
    private class MyHandler extends Handler {      
       public MyHandler(Looper looper) {
           super(looper);
       }
 
       @Override
       public void handleMessage(Message msg) {
           Log.d(TAG, "MyHandler threadid : " + Thread.currentThread().getId());
           super.handleMessage(msg);
       }
    }   
}

如果想让  HandlerThread  退出,则需要调用 mHandlerThread.quit()


猜你喜欢

转载自blog.csdn.net/wangsf1112/article/details/51306248