Handler异步消息机制实例解析

用几个简短的例子将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
结构清晰,功能定义明确
对于多个后台任务时,简单,清晰
使用的缺点:在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)

你可能感兴趣的:(android基础,android架构师之路)