zoukankan      html  css  js  c++  java
  • Android Handler机制

    前言:
    无论是现在所做的项目还是以前的项目中,都会遇见线程之间通信、组件之间通信,目前统一采用EventBus来做处理,在总结学习EventBus之前,觉得还是需要学习总结一下最初的实现方式,也算是不忘初心吧,这也是今天来学习总结Handler消息机制的一个原因。

    Handler机制产生背景
    一个Android应用程序被创建的时候都会创建一个UI主线程,但是有时我们会有一些比较耗时的操作,为了防止阻塞UI主线程,我们会将耗时的操作放到子线程中进行处理,处理完之后操作UI,但是Android不允许子线程操作UI,违背了Android单线程模型的原则(即 Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行),所以Android通过Handler消息机制来实现线程之间的通讯。

    Handler机制主要角色

        Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。 
    
        Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。 
    
        MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。 
    
        Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。 
    
        Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
    


    结合上文的的代码示例以及上图的实现流程,要使用Handler实现异步消息处理,首先我们需要在主线程中创建Handler对象并重写handleMessage()方法,然后当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handlerr将这条消息发送出去。之后这条消息会被添加到MessageQueue的队列中等待被处理,而Looper则会一直尝试从MessageQueue中取出待处理消息,最后分发回Handler的handleMessage()方法中。由于Halldler是在主线程中创建的,所以此时handleMessage()方法中的代码也会在主线程中运行,从而实现子线程通过Handler机制实现UI线程操作的目的。

    Handler机制主要运用
    1.)发送消息,在不同的线程间发送消息,使用的方法为sendXXX();

    sendMessage(Message);//发送消息,消息中可以携带参数
    sendMessageAtTime(Message, long);//未来某一时间点发送消息
    sendMessageDelayed(Message, long);//延时Nms发送消息
    

    举例:

    主线程定义Handler

    Handler mHandler = new Handler() {
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 0:
                        //完成主界面更新,拿到数据
                        String data = (String) msg.obj;
                        textView.setText(data);
                        break;
                    default:
                        break;
                }
            }
        };
    

    子线程发消息,通知Handler完成UI更新

    private void getDataFromNet() {
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    //耗时操作,完成之后发送消息给Handler,完成UI更新;
                    mHandler.sendEmptyMessage(0);
    
                    //需要数据传递,用下面方法;
                    Message msg = new Message();
                    msg.obj = "网络数据";//可以是基本类型,可以是对象,可以是List、map等;
                    mHandler.sendMessage(msg);
                }
    
            }).start();
        }
    

    2.)计划任务,在未来执行某任务,使用的方法为postXXX();

    post(Runnable);//提交计划任务马上执行
    postAtTime(Runnable, long);//提交计划任务在未来的时间点执行
    postDelayed(Runnable, long);//提交计划任务延时Nms执行
    

    示例:

    主线程定义Handler

    private Handler mHandler=new Handler();
    

    子线程提交任务更新UI

    private void getDataFromNet() {
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    //耗时操作,完成之后提交任务更新UI
                    final String data = "网络数据";
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            textView.setText(data);
                        }
                    });
                }
            }).start();
        }
    

    Handler机制扩展
    为了更加方便的使用Handler消息机制,Android也提供了几种扩展方式,内部实现都是基于Handler消息机制

    1.) Activity.runOnUiThread(Runnable)

    private void getDataFromNet() {
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    //耗时操作,完成之后提交任务更新UI
                    final String data = "网络数据";
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            textView.setText(data);
                        }
                    });
                }
            }).start();
        }
    

    2 .)View.post(Runnable)

    private void getDataFromNet() {
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    //耗时操作,完成之后提交任务更新UI
                    final String data = "网络数据";
                    textView.post(new Runnable() {
                        @Override
                        public void run() {
                            textView.setText(data);
                        }
                    });
                }
            }).start();
        }
    

    5.)使用AsyncTask代替Thread

    private void getDataFromNet() {
            MyTask task = new MyTask();
            task.execute();
        }
    
        private class MyTask extends AsyncTask {
    
            //后台线程执行时
            @Override
            protected Object doInBackground(Object... params) {
                ////耗时操作,
                String data = "网络数据";
                return data;
            }
    
            //后台线程执行结束后的操作,其中参数result为doInBackground返回的结果
            @Override
            protected void onPostExecute(Object result) {
                super.onPostExecute(result);
                textView.setText((String) result);
            }
        }
    

    参考博客:
    [1]ANDROID中HANDLER使用浅析
    https://www.cnblogs.com/panhouye/p/6494753.html
    [2]Android消息传递之Handler消息机制
    https://www.cnblogs.com/whoislcj/p/5590615.html
    [3]Android HandlerThread 总结使用
    https://www.cnblogs.com/zhaoyanjun/p/6062880.html
    [4]Android Handler 消息机制原理解析
    https://www.cnblogs.com/zhoug2020/p/12841311.html
    [5]Android Handler机制彻底梳理
    https://www.cnblogs.com/webor2006/p/11630538.html

  • 相关阅读:
    Python入门-函数进阶
    Python入门-初始函数
    Leetcode300. Longest Increasing Subsequence最长上升子序列
    Leetcode139. Word Break单词拆分
    Leetcode279. Perfect Squares完全平方数
    Leetcode319. Bulb Switcher灯泡开关
    Leetcode322. Coin Change零钱兑换
    二叉树三种遍历两种方法(递归和迭代)
    Leetcode145. Binary Tree Postorder Traversal二叉树的后序遍历
    Leetcode515. Find Largest Value in Each Tree Row在每个树行中找最大值
  • 原文地址:https://www.cnblogs.com/shujk/p/14630348.html
Copyright © 2011-2022 走看看