安卓学习笔记之HandlerThread

一 、HandlerThread简介

从字面意思上看,它既与Handler有关系又与Thread有联系。确实如此,它继承自Thread,是一个线程类,同时又内嵌Looper对象。因此,用它开启的线程的内部可以直接创建一个Handler,并可以与主线程交互。

关于Looper和Handler的协作请参考安卓学习笔记之android消息机制

二、源码分析

1、构造方法,用于设置线程名和初始化线程优先级。务必要通过start方法来开启线程

  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 
 */
public HandlerThread(String name, int priority) {
    super(name);
    mPriority = priority;
}

2、run方法,初始化Looper对象

可以看到HandlerThread内置了Looper消息循环。onLooperPrepared方法在Looper开始loop之前,做一些初始化或设置。普通Thread的run方法一般都做一些耗时操作,但在此run方法做的是创建Lopper并开启消息轮循,我们可以在线程的外部通过handler发消息让它做一些事情。注意,不要试图重写其run方法并做耗时操作!

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

/**
 * Call back method that can be explicitly overridden if needed to execute some
 * setup before Looper loops.
 */
protected void onLooperPrepared() {
}

3、获取Looper对象,用于关联一个Handler。当线程启动但Looper没有创建完成时需等待。

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

4、 资源回收

由于run方法不会自动停止(Looper.loop()的原因),所以当我们不使用HandlerThread时,可以调用它的quit或quitSafely方法退出线程,否则线程资源得不到回收。

// 直接退出,不处理余留消息
 /**
 * Quits the handler thread's looper.
 * <p>
 * Causes the handler thread's looper to terminate without processing any
 * more messages in the message queue.
 */
    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.
 */
public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quitSafely();
        return true;
    }
    return false;
}

三、简单案例

模拟一个下载任务,在HandlerThread线程中执行耗时操作,并向主线程发送消息以更新UI,当任务完成时,主线程会向子线程发送消息以停止子线程的消息轮循。

    package com.yu.threadspool;

    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.Message;
    import android.os.SystemClock;
    import android.util.Log;
    import android.widget.TextView;

    public class HandlerThreadTest extends Activity {
    public static final int MSG_FROM_MAIN = 0;  
    public static final int MSG_FROM_THREAD = 1;
    public static final int MSG_TASK_DONE = 2;
    public static final int MSG_QUIT = 3;
    HandlerThread handlerThread;
    Handler threadHandler; //子线程
    int count = 0;

    TextView tv; // 显示进度

    Handler mainHanlder = new Handler() {  // 主线程handler

        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_FROM_THREAD:
                tv.setText((String) msg.obj);
                break;

            case MSG_TASK_DONE:
                tv.setText("完成!");
                threadHandler.obtainMessage(MSG_QUIT).sendToTarget();
                break;
            }
        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_thread);
        tv = (TextView) findViewById(R.id.tv_text);

        initHandlerThread();

        // 做一些事情,在子线程
        threadHandler.post(new Runnable() {
            public void run() {
                Log.e("TAG", "thread:" + Thread.currentThread().getName());
                while (count < 100) {
                    ++count;
                    Log.e("TAG", "count:" + count);
                    SystemClock.sleep(200); // 模拟耗时
                    Message msg = mainHanlder.obtainMessage(MSG_FROM_THREAD,
                            String.valueOf(count));
                    msg.sendToTarget(); // 向主线程发送消息,更新UI
                }
                // 发送任务完成消息
                mainHanlder.obtainMessage(MSG_TASK_DONE).sendToTarget();

            };
        });
    }

    /**
     * 初始化HandlerThread
     */
    private void initHandlerThread() {
        handlerThread = new HandlerThread("HandlerThread#1");
        handlerThread.start(); // 务必要调用,且必须在关联Handler之前
        threadHandler = new Handler(handlerThread.getLooper())// 将threadHandler与handlerThread线程关联
        {
            @SuppressLint("NewApi") @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == MSG_QUIT) {

                    handlerThread.getLooper().quitSafely(); // 退出消息轮循,释放资源
                    Log.e("TAG", Thread.currentThread().getName()+"退出");
                }

            }
        };

    }
}

执行结果

09-08 09:49:45.132: E/TAG(2162): thread:HandlerThread#1
09-08 09:49:45.132: E/TAG(2162): count:1
09-08 09:49:45.332: E/TAG(2162): count:2
09-08 09:49:45.532: E/TAG(2162): count:3
09-08 09:49:45.742: E/TAG(2162): count:4
09-08 09:49:45.942: E/TAG(2162): count:5
        ... ... (省略部分)
09-08 09:50:04.332: E/TAG(2162): count:96
09-08 09:50:04.532: E/TAG(2162): count:97
09-08 09:50:04.742: E/TAG(2162): count:98
09-08 09:50:04.942: E/TAG(2162): count:99
09-08 09:50:05.142: E/TAG(2162): count:100
09-08 09:50:05.342: E/TAG(2162): HandlerThread#1退出
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值