频道栏目
首页 > 资讯 > Android > 正文

Android多线程消息处理机制 HandlerThread案例分析

16-08-20        来源:[db:作者]  
收藏   我要投稿
Main线程已经有了looper且已启动,意味着包含了消息队列。
所有没有指定looper对象而创建的handler,使用的都是main的looper。
这样的handler发送的message都放到了main线程的looper管理的消息队列中了。

发现有HandlerThread这个类,以前没用过,总以为是在Thread中内置了一个Handler。
在面试中也总是被问到,很心烦,于是索性来研究一下,正好前面也整体分析了looper,handler等技术。

先来看下源码吧:

/**
 * 创建一个新的线程类,同时包含有一个Looper. 然后可以使用这个Looper创建一个Handler.
 * Note:包含有一个Looper意味着什么?
 * 启动线程时启动looper消息循环,looper内置有messageQueue。这个线程专用来处理消息的了
 * 看文章:Android多线程消息处理机制,http://blog.csdn.net/fesdgasdgasdg/article/details/52081773
 */
public class HandlerThread extends Thread {
    int mPriority;//线程优先级
    int mTid = -1;//进程id
    Looper mLooper;//核心对象


    public HandlerThread(String name) {
        super(name);
		//获取线程默认的优先级,0
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    /**
     * 构造函数
     * @param name 线程名称
     * @param priority 线程优先级. 必须从android.os.Process获取,而不能从java.lang.Thread获取.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    /**
     * 如果需要在looper循环前执行一些操作时,可以显式的重写此方法
     */
    protected void onLooperPrepared() {
    }


	/**
	 * 线程的run方法,在线程start()后,就开始执行run方法,
	 * 在run里面Looper.prepare()创建looper...
	 * 此内容参考:Android多线程消息处理机制,http://blog.csdn.net/fesdgasdgasdg/article/details/52081773
	 */
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();//循环前的回调
        Looper.loop();
        mTid = -1;
    }
    
    /**
     * 此方法返回当前线程关联的looper,
     * 如果当前线程没有启动或者已停止等原因,此方法返回null
     * 如果此方法已经启动,此方法将阻塞知道looper被初始化 
     * @return The looper.
     */
    public Looper getLooper() {
	    //如果当前线程不处在运行状态,则返回null
        if (!isAlive()) {
            return null;
        }
        
        // 如果此方法已经启动,此方法将阻塞知道looper被初始化
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }


    /**
     * 退出线程的looper循环.
     * 使looper线程终止消息循环,不再处理消息队列中的任何消息
	 * 当looper调用quit之后,任何尝试post message到messageQueue中的操作都会失败
     * 比喻:Handler的sendMessage(Message)方法会返回false
     * 使用这个方法可能不安全,因为在looper停止之前可能有message没有被执行。
     * 考虑使用quitSafely()方法代替quit()方法,以确保所有待完成的工作有序完成。
     * @return 如果looper调用了quit,则返回true。如果线程还没有开始执行则返回false
     *
     * @see #安全退出
     */
    public boolean quit() {
        Looper looper = getLooper();//获取当前线程的looper
        if (looper != null) {
            looper.quit();
            return true;//成功的调用了quit,返回true
        }
        return false;
    }


    /**
     * 安全的退出线程looper循环。
     * 当messageQueue中所有已到期的message都处理完后,终止looper线程的消息循环。
     * 但是由于延时的消息需要等待,故这些消息将不会被处理。
     * Pending delayed messages with due times in the future will not be delivered.
     * 当looper调用quit之后,任何尝试post message到messageQueue中的操作都会失败
     * 比喻:Handler的sendMessage(Message)方法会返回false
	 * 如果线程没有被启动,或者已经结束则返回false。否则在调用quitSafely()之后返回true。
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }


    /**
     * 返回此线程的标识符. 参考Process.myTid().
     */
    public int getThreadId() {
        return mTid;
    }
}

 

这么一分析,是否都清楚了?无非就是个Thread,在里面内置了一个Looper,looper会自带一个MessageQueue。

在Thread的run方法中使用looper.prepqre()创建了looper。然后赋给当前线程的looper成员变量,供外面的handler使用。

接着调用looper.loop()方法启动消息循环。

前面也讲过可以自己创建LooperThread线程,HandlerThread就是google提供的经典实例,只不过HandlerThread里面提供了线程安全访问,退出消息循环等方法。

具体的用法简单的1C, 下面就用自己创建的LooperThread为例,如果你不喜欢的话,直接把LooperThread替换成现有的HandlerThread类即可。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Handler mHandler;
    private LooperThread thread;
    private TextView show;
    private Button start;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        show = (TextView) findViewById(R.id.show);
        start = (Button) findViewById(R.id.start);
        start.setOnClickListener(this);
        init();
    }

    private void init() {
        thread = new LooperThread();
        thread.start();
        while (thread.getLooper() == null) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        mHandler = new Handler(thread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                //处理消息
                Log.v("looper的handler", Thread.currentThread().getName() + " - " + msg.what);
                //修改textview会报错的。
                //show.setText("");
            }
        };
    }

    @Override
    public void onClick(View v) {
        mHandler.sendEmptyMessage(200);
    }

    /**
     * Looper线程
     */
    class LooperThread extends Thread {
        private Looper looper;

        public Looper getLooper() {
            return looper;
        }

        @Override
        public void run() {
            super.run();
            Looper.prepare();
            looper = Looper.myLooper();
            Looper.loop();
        }
    }
}


 

初始化的时候先创建LooperThread线程,且启动。

然后里面就会有looper了。

在创建handler的时候传入上面的looper。那么此时的handler已和LooperThread的消息队列绑定了。这个handler所发送和处理的消息只经过LooperThread的消息循环,

跟UI线程已有的消息循环没关系了。

 

最后有一点需要注意:

 

public void handleMessage(Message msg) {
                //处理消息
                Log.v("looper的handler", Thread.currentThread().getName() + " - " + msg.what);
                //修改textview会报错的。
                //show.setText("");
            }

这个处理消息的方法,不能再处理UI线程创建的UI控件了。如果你真心想修改某一个ui,那的保证这个ui必须在LooperThread里面创建和添加到window中去。

相关TAG标签
上一篇:亚马逊不看好win10?推出应用仅支持最基本功能
下一篇:Google云端数据库软件正式推出,继续在企业云端市场努力
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站