Handler异步消息机制实例解析

来源:互联网 发布:自动修改mac地址修改器 编辑:程序博客网 时间:2024/05/19 19:33

用几个简短的例子将Handler相关的知识点整理下,方便以后查阅也方便大家快速掌握本知识点。

名词解释:
Message 是线程之间传递的消息,它可以在内部携带少量信息,用于在不同线程之间交换数据。
MessageQueue 是消息队列,它主要用于存放所有由 Handler发送过来的消息,这部分消息会一直在消息队列中,等待被处理。
Handler 即处理者,它主要用于发送和处理消息。发送消息一般使用 handler 的 sendMessage(),处理消息会调用 handleMessage()。
Looper 是每个线程中 MessageQueue的管家,调用 loop()方法后就会进入到一个无限循环当中,然后每当发现 MessageQueue中存在一条消息,就会将其取出,并传递到 handleMessage()方法当中。

注意:每个线程中只会有一个Looper对象,一个MessageQueue。Handler依附于创建时所在的线程。

下面就用代码示例其中的原理吧~

目标场景
主线程向子线程发消息,子线程接收到主线程的消息后给主线程发个通知,然后主线程更新UI。

实现步骤:
1,主线程给子线程发消息,子线程接收消息。
既然是子线程接收消息,说明handleMessage是在子线程中。Handler是依附于子线程。代码如下:

 private LoopThread loopThread;      @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ...        //开启实现了Runnable接口的子线程        new Thread(loopThread = new LoopThread()).start();    }    /**     * 通过实现Runnable接口的方式生成一个子线程     */    public class LoopThread implements Runnable {        public Handler mHandler = null;        @Override        public void run() {            Looper.prepare();            mHandler = new Handler() {                public void handleMessage(Message msg) {                    handleMsgAndTodo(msg);                }            };            Looper.loop();        }    }

一个实现了Runnable接口的子线程,在子线程中实例化了handler并通过handleMessage接收消息。注意此处有Looper.prepare();和 Looper.loop();说明是子线程自身新建的消息管家looper(主线程里默认建立了自己的looper)。
主线程发消息就可以直接调用”loopThread.mHandler.sendEmptyMessage(1);”(LoopThread是一个实现了Runnable接口的类)。

接下来子线程接受处理消息与主线程处理消息都封装handleMsgAndTodo(msg)方法中了。代码如下:

    /**     * 对接收到的消息进行处理     * @param msg     */    private void handleMsgAndTodo(Message msg) {        switch (msg.what) {            case 0:                showMessageTv.setText("2---这是更新后的UI");                Log.d("从子线程发消息到主线程", "接收成功");                break;            case 1:                Log.d("从主线程发消息到子线程", "接收成功");                handler.sendEmptyMessage(0);                Log.d("从子线程发消息到主线程", "准备发送");                break;            default:                break;        }    }

刚刚主线程发的消息msg.what = 1,这里接收到消息立即给主线程发消息msg.what = 0,注意用的是handler而不是mHandler或者loopThread.mHandler,这里的handler是在主线程中实例化。代码如下:

    /**     * 接收异步消息更新UI     */    Handler handler = new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            handleMsgAndTodo(msg);        }    };

此处的handler是依附于主线程的,可以直接在其中更新UI。
另外,还有几个方法也是基于异步消息机制。
比如在子线程中更新UI的例子:

    /**     * 调用hander.post()方法更新主线程UI     */    private void handerpost() {        new Thread(new Runnable() {            @Override            public void run() {                //...省略进行的耗时操作代码,以下三种方法实现子线程给主线程发消息//               handler.sendEmptyMessage(0); //这几个方法在子线程中更新UI等效于在主线程中调用handleMessage()更新UI——hander.post(),view.post(), runOnUiThread(),其原理都是通过异步消息处理机制实现的。//                handler.post(new Runnable() {//                  @Override//                  public void run() {//                  showMessageTv.setText("1---这是更新后的UI");//                    }//                });//在子线程中new Handler(Looper.getMainLooper())就表示其handleMessage()方法里的事情是在主UI线程去处理的,这个Handler其实是与主线程绑定的。        Handler handler2 = new Handler(getMainLooper()){                @Override                public void handleMessage(Message msg) {                   super.handleMessage(msg);                   showMessageTv.setText("3---这是更新后的UI");                }         };                handler2.sendEmptyMessage(0);        }    }).start();  }

如上几段代码中的方法,无异于都是调用主线程中的handler进行发消息更新UI。另一个在子线程中实例化的handler2,也是因为共用了主线程的looper,即与主线程维护同一个消息队列,所以相当于在主线程更新UI。

自我理解:
哪个线程要接收消息,就在该线程实例化Handler来调用handleMessage。若主线程向子线程发消息,则需要用到 Looper.prepare()和 Looper.loop(),并在子线程中实例化Handler来调用handleMessage()。

在子线程中new Handler(Looper.getMainLooper())就表示其handleMessage()方法里的事情是在主UI线程去处理的,这个Handler其实是与主线程绑定的。
hander.post(),view.post(), runOnUiThread()这几个方法在子线程中更新UI等效于在主线程中调用handleMessage更新UI——其原理都是通过异步消息处理机制实现的。

Handler+Thread与HandlerThread区别:
HandlerThread就是将含有消息队列的Looper与Thread封装在一起的写法,可以直接在子线程的接受的消息处理耗时任务。

Handler+Thread与 AsyncTask优缺点
1,AsyncTask,是Android提供的轻量级的异步类,直接继承AsyncTask类进行异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
使用的优点:简单,快捷(只是代码上轻量一些,而实际上要比handler更耗资源),过程可控
使用的缺点:在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
2,Handler+Thread
结构清晰,功能定义明确
对于多个后台任务时,简单,清晰
使用的缺点:在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)

1 0
原创粉丝点击