Android线程

来源:互联网 发布:淘宝宝贝宣言词怎么写 编辑:程序博客网 时间:2024/06/06 18:37

概述
HandlerThread就是可以处理消息循环的线程,它是一个拥有Looper的线程,可以处理消息循环。简单理解就是一个Thread,内部使用了Looper。
我们都知道,除了在主线程,其他线程必须通过Looper.prepare()创建Looper、Looper.loop()开启消息循环。
举个栗子:

import android.os.Bundle;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;public class MainActivity extends AppCompatActivity {    private Button mBtnStart;    private Handler mChildThreadHandler; //子线程的Handler    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Thread thread = new ChildThread();        thread.start();        mBtnStart = (Button)findViewById(R.id.btn_start);        mBtnStart.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                mChildThreadHandler.sendEmptyMessage(0);            }        });    }    class ChildThread extends Thread{        @Override        public void run(){            Looper.prepare(); //给线程创建一个消息循环            mChildThreadHandler = new Handler(){                @Override                public void handleMessage(Message msg){                    super.handleMessage(msg);                    mBtnStart.setText("更新按钮文本");                }            };            Looper.loop(); //开始消息循环        }    }}

我的天,在Handler更新UI,出现如下异常。

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

提示只有创建视图(主线程)的线程才能更新UI。mChildThreadHandler是在子线程中开启消息循环,所以没办法切换到主线程中更新UI。

HandlerThread就是在Thread中开启消息循环,但为什么要使用HandlerThread呢?当把Looper转到子线程处理,可以减轻主线程的工作量,使主界面更流畅。

再举一个栗子
用一个Handler更新UI,另一个Handler用于异步耗时任务
布局这里就不贴了,就一个Button一个TextView

import android.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends AppCompatActivity {    private Button mBtnStart;    private TextView mTvShow;    private Handler mChildHandler; //子线程的Handler    private HandlerThread mHandlerThread; //创建异步HandlerThread    private int flag;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mTvShow = (TextView)findViewById(R.id.tv_show);        mBtnStart = (Button)findViewById(R.id.btn_start);        mBtnStart.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                mChildHandler.sendEmptyMessage(0);            }        });        mHandlerThread = new HandlerThread("handlerThread");        mHandlerThread.start();        mChildHandler = new Handler(mHandlerThread.getLooper(), new Handler.Callback() {            @Override            public boolean handleMessage(Message message) {                //这里执行耗时操作后 更新UI                Message msg = Message.obtain();                msg.arg1 = ++flag;                msg.what = 0;                mUpdateUIHandler.sendMessage(msg);                return true;            }        });    }    private Handler mUpdateUIHandler = new Handler(){        @Override        public void handleMessage(Message message){            //这里用于更新UI            switch (message.what){                case 0:                    mTvShow.setText("得到的数据"+message.arg1);                    break;            }        }    };@Overrideprotected void onDestroy() {    super.onDestroy();    mHandlerThread.quit();}}

效果
这里写图片描述

HandlerThread源码

public class More ...HandlerThread extends Thread {       int mPriority;       int mTid = - ;       Looper mLooper;       public More ...HandlerThread(String name) { //重点1           super(name);           mPriority = Process.THREAD_PRIORITY_DEFAULT;       }       public More ...HandlerThread(String name, int priority) {           super(name);           mPriority = priority;       }       protected void More ...onLooperPrepared() {       }       @Override       public void More ...run() { //重点2           mTid = Process.myTid();           Looper.prepare(); //重点3           synchronized (this) {               mLooper = Looper.myLooper();               notifyAll();           }           Process.setThreadPriority(mPriority);           onLooperPrepared();           Looper.loop(); //重点4           mTid = - ;       }      public Looper More ...getLooper() {            if (!isAlive()) {               return null;           }           synchronized (this) {               while (isAlive() && mLooper == null) {                   try {                       wait();                   } catch (InterruptedException e) {                   }               }           }           return mLooper;       }       public boolean More ...quit() { //重点5           Looper looper = getLooper();           if (looper != null) {               looper.quit();               return true;           }           return false;       }       public boolean More ...quitSafely() { //重点6           Looper looper = getLooper();           if (looper != null) {               looper.quitSafely();               return true;           }           return false;       }       public int More ...getThreadId() {           return mTid;       }   }

HandlerThread是一个Thread,传入的参数就是该线程的名称。
重点3、4通过内部自己创建Looper,开启消息循环,会一直循环,当明确不需要的时候,要记得销毁。
5、6的两个方法分别的作用为:
Looper的quit():将MessageQueue消息池的消息全部清空,无论是延迟消息还是非延迟消息。
Looper的quitSafely():只会清空MessageQueue消息池中所有的延迟消息,那些非延迟的消息会发给Handler去处理。
Looper的quit方法从API Level 1就存在了,但是Looper的quitSafely方法从API Level 18才添加进来。
再次强调:HandlerThread是串行执行,拥有自己的消息队列,不会阻塞UI线程。

原创粉丝点击