美文网首页Android开发Android开发经验谈Android技术知识
详解Android Handler 机制 (一)用法全解

详解Android Handler 机制 (一)用法全解

作者: Daybreaks | 来源:发表于2020-05-02 01:18 被阅读0次
    mm.jpeg
    ps:这是关于Android Handler 机制的第一篇文章,主要来说一下Handler的用法,本文尽量归纳完全,如有缺漏,欢迎补充。

    Handler的主要作用是切换线程,以及隐式的充当接口回调的作用,当子线程网络请求结束后,通过handler发送消息给主线程,这一点都不多说了。

    常用用法

    先来贴一种最常用的用法:

        private Handler mHandler = new Handler() {
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                //...处理逻辑
            }
        };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mHandler.sendEmptyMessage(MainActivity.HANDLER_MAIN_CODE);
                }
            });
    

    这种方法是大家最常用的,使用Handler的匿名内部类,去覆写handleMessage方法,来处理当消息到达时所做出的反应。这里埋一个伏笔:

    报黄

    这里IDEA在提示可能会发生内存泄漏,具体为什么会发生内存泄漏,针对问题的具体分析以及最后封装SafeHandler,我会在第三篇Handler文章中讲述。

    Message

    Message是Handler发送的消息的数据载体。

    先看一下Message,Message用来承载数据,承载数据的实现是Message的几个public的成员变量:

        public int what;
    
        public int arg1;
    
        public int arg2;
    
        public Object obj;
      
    
    • what: 这是一个int类型的变量,通常用来在handleMessage处做判断,当一个handler发送多条message时,用来辨别这是哪一条消息
    • arg1,arg2,当发送的Message需要承载的data是整数时,可以简单的使用这两个参数来承载。
    • Obj,这是一个Object对象,因为有这个变量,我们所能承载的data就多样化了,只要是对象都可以通过message传递,List、数组等等。
      另外Message还提供了通过Bundle来传递数据:
      Bundle也是一个数据载体,这里就不多说了。
    /**
         * Like getData(), but does not lazily create the Bundle.  A null
         * is returned if the Bundle does not already exist.  See
         * {@link #getData} for further information on this.
         * @see #getData()
         * @see #setData(Bundle)
         */
        public Bundle peekData() {
            return data;
        }
    
        /**
         * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members
         * as a lower cost way to send a few simple integer values, if you can.
         * @see #getData()
         * @see #peekData()
         */
        public void setData(Bundle data) {
            this.data = data;
        }
    
    Message池

    Message中维持着一个Message池,所以通常我们无需new Message(),可以调用:
    Message message = Message.obtain();,节省内存空间。

    Handler处理消息

    Handler处理消息除了文章开头所说到的一种,其实还有两种:
    message的callback和handler的mCallback,一共有三种,为什么我可以这么说呢?下面上源码

    public void dispatchMessage(@NonNull Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    这个dispatchMessage()方法是在Lopper.loop方法的无限循环中调用的:

        for(;;) {
            ...
            msg.target.dispatchMessage(msg);
            ...
        }
    

    这个msg就是我们发送的消息,target就是我们发送消息的handler。这里看不懂的也没关系,毕竟涉及到源码,之后的第二篇会将。现在只需要知道这个dispathchMessage方法是在消息接收处调用的。然后继续返回去看这个方法的内部实现。
    这个方法通过三层if-else嵌套,也就规定了这三种Handler处理消息的方法的优先级:


    flowchart.png

    可以看到我们常用的第三种方法,覆写handlerMessage是优先级最低的。

    msg.callback

    既然是msg的一个属性,那么肯定是通过msg承载callback来发送出去,先看一下callback的定义

        @UnsupportedAppUsage
        /*package*/ Runnable callback;
    

    这是一个Runnable,然后看一下handler的handleCallback(msg);方法:

    private static void handleCallback(Message message) {
            message.callback.run();
    }
    

    这样我们就知道了,消息接受处在收到message之后,如果message的callback不为空,就调用这个callback的run方法。下面看一个例子:

        private Handler mHandler = new Handler();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "消息接受后执行这段代码,这段代码运行在主线程"
                                                      ,Toast.LENGTH_SHORT).show();
                        }
                    };
                    Message message = Message.obtain(mHandler, runnable);
                    mHandler.sendMessage(message);
                }
            });
    }
    
    mHandler.mCallback

    这个方法其实和匿名内部类的写法大同小异,只不过是把覆写的handleMessage方法中的逻辑转移到mHandler的mCallback中,下面直接上代码:

    Handler.Callback callback = new Handler.Callback() {
          @Override
          public boolean handleMessage(@NonNull Message msg) {
              Toast.makeText(MainActivity.this, "收到消息", Toast.LENGTH_SHORT).show();
              return true;
          }
      };
    
      private Handler mHandler = new Handler(callback);
    
    
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
    
          findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  mHandler.sendMessage(Message.obtain());
              }
          });
    }
    

    注意handleMessage的返回时,如果返回true,那么表示处理条消息,不再向下执行。如果返回false,那么表示没有成功处理这条消息,接着向下执行,也是就执行Handler的handleMessage方法

    Handler.Callback callback = new Handler.Callback() {
           @Override
           public boolean handleMessage(@NonNull Message msg) {
               Toast.makeText(MainActivity.this, "收到消息", Toast.LENGTH_SHORT).show();
               //...处理消息
               if (...) {
                   return false;
               }
               return true;
           }
       };
    
    
       private Handler mHandler = new Handler(callback) {
           @Override
           public void handleMessage(@NonNull Message msg) {
               super.handleMessage(msg);
               Toast.makeText(MainActivity.this, 
                       "如果callback的handleMessage返回false,那么接着执行这里"
                       , Toast.LENGTH_SHORT).show();
           }
       };
    
    
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_main);
    
           findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   mHandler.sendMessage(Message.obtain());
               }
           });
    }
    

    总结

    这样终于把Handler的三种处理消息的用法搞清楚了,需要注意的是,第一种方法和其他两种是互斥的,只要Message的callback不为空,那么就执行callback中的run方法的逻辑,而不会执行handleMessage。

    我们需要知道的是,Handler机制在Android中的作用绝对不仅仅是给开发者切换线程,Handler机制在维持一个APP的正常运作。一个点击事件,启动一个Activity等等基础功能,都离不开Handler。具体是如何运作的,就要看Handler机制的源码了。

    既然都看完了,大家点个赞再走呀

    相关文章

      网友评论

        本文标题:详解Android Handler 机制 (一)用法全解

        本文链接:https://www.haomeiwen.com/subject/nlqhghtx.html