美文网首页Android开发工程师VAndroid学习程序媛开发笔记
Android:这是一份Handler消息传递机制 的使用教程

Android:这是一份Handler消息传递机制 的使用教程

作者: Carson带你学安卓 | 来源:发表于2018-03-12 09:24 被阅读2434次

    前言

    • Android开发的多线程应用场景中,Handler机制十分常用

    • 今天,我将献上一份 Handler机制的使用教程 ,希望你们会喜欢

    阅读本文前,请先阅读:Android Handler:图文解析 Handler通信机制 的工作原理


    目录

    示意图

    1. Handler 机制简介

    • 定义
      一套 Android 消息传递机制 / 异步通信机制

    • 作用

    在多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现 工作线程对UI的更新处理,最终实现异步消息的处理

    示意图
    • 为什么要用 Handler消息传递机制
      答:多个线程并发更新UI的同时 保证线程安全。具体描述如下
    示意图
    • 总结
      使用Handler的原因:将工作线程需操作UI的消息 传递 到主线程,使得主线程可根据工作线程的需求 更新UI从而避免线程操作不安全的问题

    2. 相关概念

    关于 Handler 机制中的相关概念如下:

    在下面的讲解中,我将直接使用英文名讲解,即 HandlerMessageMessage QueueLooper,希望大家先熟悉相关概念

    示意图

    3. 使用方式

    • Handler使用方式 因发送消息到消息队列的方式不同而不同
    • 共分为2种:使用Handler.sendMessage()、使用Handler.post()

    4. 使用步骤

    方式1:使用 Handler.sendMessage()

    在该使用方式中,又分为2种:新建Handler子类(内部类)、匿名 Handler子类

    但本质相同,即 继承了Handler类 & 创建了子类

    /** 
      * 方式1:新建Handler子类(内部类)
      */
    
        // 步骤1:自定义Handler子类(继承Handler类) & 复写handleMessage()方法
        class mHandler extends Handler {
    
            // 通过复写handlerMessage() 从而确定更新UI的操作
            @Override
            public void handleMessage(Message msg) {
             ...// 需执行的UI操作
                
            }
        }
    
        // 步骤2:在主线程中创建Handler实例
            private Handler mhandler = new mHandler();
    
        // 步骤3:创建所需的消息对象
            Message msg = Message.obtain(); // 实例化消息对象
            msg.what = 1; // 消息标识
            msg.obj = "AA"; // 消息内容存放
    
        // 步骤4:在工作线程中 通过Handler发送消息到消息队列中
        // 可通过sendMessage() / post()
        // 多线程可采用AsyncTask、继承Thread类、实现Runnable
            mHandler.sendMessage(msg);
    
        // 步骤5:开启工作线程(同时启动了Handler)
        // 多线程可采用AsyncTask、继承Thread类、实现Runnable
    
    
    /** 
      * 方式2:匿名内部类
      */
       // 步骤1:在主线程中 通过匿名内部类 创建Handler类对象
                private Handler mhandler = new  Handler(){
                    // 通过复写handlerMessage()从而确定更新UI的操作
                    @Override
                    public void handleMessage(Message msg) {
                            ...// 需执行的UI操作
                        }
                };
    
      // 步骤2:创建消息对象
        Message msg = Message.obtain(); // 实例化消息对象
      msg.what = 1; // 消息标识
      msg.obj = "AA"; // 消息内容存放
      
      // 步骤3:在工作线程中 通过Handler发送消息到消息队列中
      // 多线程可采用AsyncTask、继承Thread类、实现Runnable
       mHandler.sendMessage(msg);
    
      // 步骤4:开启工作线程(同时启动了Handler)
      // 多线程可采用AsyncTask、继承Thread类、实现Runnable
    
    

    方式2:使用Handler.post()

    // 步骤1:在主线程中创建Handler实例
        private Handler mhandler = new mHandler();
    
        // 步骤2:在工作线程中 发送消息到消息队列中 & 指定操作UI内容
        // 需传入1个Runnable对象
        mHandler.post(new Runnable() {
                @Override
                public void run() {
                    ... // 需执行的UI操作 
                }
    
        });
    
        // 步骤3:开启工作线程(同时启动了Handler)
        // 多线程可采用AsyncTask、继承Thread类、实现Runnable
    

    5. 实例讲解

    本文将用实例逐个讲解 Handler的用法

    注:

    1. 由于Handler的作用 = 将工作线程需操作UI的消息 传递 到主线程,使得主线程可根据工作线程的需求 更新UI,从而避免线程操作不安全的问题
    2. 故下文的实例 = 1个简单 “更新UI操作” 的案例
    3. 主布局文件相同 = 1个用于展示的TextView,具体如下:

    布局代码:activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        tools:context="com.example.carson_ho.handler_learning.MainActivity">
    
        <TextView
            android:id="@+id/show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="" />
    </RelativeLayout>
    

    实例的源码地址:Carson_Ho的Github:Handler
    (建议:先fork下来再看,效果会更好哦!)

    5.1 使用 Handler.sendMessage()

    方式1:新建Handler子类(内部类)
    • 具体使用
    public class MainActivity extends AppCompatActivity {
        
        public TextView mTextView;
        public Handler mHandler;
    
        // 步骤1:(自定义)新创建Handler子类(继承Handler类) & 复写handleMessage()方法
        class Mhandler extends Handler {
    
            // 通过复写handlerMessage() 从而确定更新UI的操作
            @Override
            public void handleMessage(Message msg) {
                // 根据不同线程发送过来的消息,执行不同的UI操作
                // 根据 Message对象的what属性 标识不同的消息
                switch (msg.what) {
                    case 1:
                        mTextView.setText("执行了线程1的UI操作");
                        break;
                    case 2:
                        mTextView.setText("执行了线程2的UI操作");
                        break;
                }
            }
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mTextView = (TextView) findViewById(R.id.show);
    
            // 步骤2:在主线程中创建Handler实例
            mHandler = new Mhandler();
           
            // 采用继承Thread类实现多线程演示
            new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                     // 步骤3:创建所需的消息对象
                     Message msg = Message.obtain();
                     msg.what = 1; // 消息标识
                     msg.obj = "A"; // 消息内存存放
    
                     // 步骤4:在工作线程中 通过Handler发送消息到消息队列中
                     mHandler.sendMessage(msg);
                }
            }.start();
            // 步骤5:开启工作线程(同时启动了Handler)
    
            // 此处用2个工作线程展示
            new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(6000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 通过sendMessage()发送
                     // a. 定义要发送的消息
                     Message msg = Message.obtain();
                     msg.what = 2; //消息的标识
                     msg.obj = "B"; // 消息的存放
                     // b. 通过Handler发送消息到其绑定的消息队列
                     mHandler.sendMessage(msg);
                }
            }.start();
    
        }
    }
    
    • 运行结果
    示意图
    方式2:匿名内部类
    • 具体使用
    public class MainActivity extends AppCompatActivity {
        
        public TextView mTextView;
        public Handler mHandler;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mTextView = (TextView) findViewById(R.id.show);
    
            // 步骤1:在主线程中 通过匿名内部类 创建Handler类对象
            mHandler = new Handler(){
                // 通过复写handlerMessage()从而确定更新UI的操作
                @Override
                public void handleMessage(Message msg) {
                    // 根据不同线程发送过来的消息,执行不同的UI操作
                    switch (msg.what) {
                        case 1:
                            mTextView.setText("执行了线程1的UI操作");
                            break;
                        case 2:
                            mTextView.setText("执行了线程2的UI操作");
                            break;
                    }
                }
            };
            // 采用继承Thread类实现多线程演示
            new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                     // 步骤3:创建所需的消息对象
                     Message msg = Message.obtain();
                     msg.what = 1; // 消息标识
                     msg.obj = "A"; // 消息内存存放
    
                     // 步骤4:在工作线程中 通过Handler发送消息到消息队列中
                     mHandler.sendMessage(msg);
                }
            }.start();
            // 步骤5:开启工作线程(同时启动了Handler)
    
            // 此处用2个工作线程展示
            new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(6000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 通过sendMessage()发送
                     // a. 定义要发送的消息
                     Message msg = Message.obtain();
                     msg.what = 2; //消息的标识
                     msg.obj = "B"; // 消息的存放
                     // b. 通过Handler发送消息到其绑定的消息队列
                     mHandler.sendMessage(msg);
                }
            }.start();
    
        }
    
    }
    
    • 运行结果
    示意图

    5.2 使用 Handler.post()

    • 具体使用
    public class MainActivity extends AppCompatActivity {
        
        public TextView mTextView;
        public Handler mHandler;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mTextView = (TextView) findViewById(R.id.show);
    
            // 步骤1:在主线程中创建Handler实例
            mHandler = new Handler();
    
            // 步骤2:在工作线程中 发送消息到消息队列中 & 指定操作UI内容
            new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 通过psot()发送,需传入1个Runnable对象
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            // 指定操作UI内容
                            mTextView.setText("执行了线程1的UI操作");
                        }
    
                    });
                }
            }.start();
            // 步骤3:开启工作线程(同时启动了Handler)
    
            // 此处用2个工作线程展示
            new Thread() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(6000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            mTextView.setText("执行了线程2的UI操作");
                        }
    
                    });
                }
            }.start();
    
        }
    
    }
    
    • 运行结果


      示意图

    至此,关于Handler的异步消息传递机制的使用讲解完毕。


    6. 总结

    • 本文对Handler异步通信传递机制的使用进行了全面讲解
    • 下面我将继续深入讲解 Android中的Handler异步通信传递机制的相关知识,如 工作机制流程、源码解析等,有兴趣可以继续关注Carson_Ho的安卓开发笔记

    请点赞!因为你的鼓励是我写作的最大动力!

    相关文章阅读
    Android开发:最全面、最易懂的Android屏幕适配解决方案
    Android事件分发机制详解:史上最全面、最易懂
    Android开发:史上最全的Android消息推送解决方案
    Android开发:最全面、最易懂的Webview详解
    Android开发:JSON简介及最全面解析方法!
    Android四大组件:Service服务史上最全面解析
    Android四大组件:BroadcastReceiver史上最全面解析


    欢迎关注Carson_Ho的简书!

    不定期分享关于安卓开发的干货,追求短、平、快,但却不缺深度

    相关文章

      网友评论

      • Spur2:不错 有理论 有实例 感谢博主
      • 小学留了三年:真心的谢谢博主的付出。
      • 30a6055923a8:看完了,大佬写的很透彻,终于明白了Handler的工作机制,谢谢大佬
        同时借大佬位置推荐一下我的文章~
        搭建服务器帆蔷上古戈:
        https://www.jianshu.com/p/cd7c51aab95a
      • Newamber:多谢分享,大佬我看了一圈,好像没发现讲关于适配虚拟导航栏的,能考虑以后开个章节讲讲吗, 我现在实习的公司做的是react-native应用,在有虚拟导航栏的手机上运行会出现白条覆盖本身的UI元素,找了网上的办法都不行,也不知道如何反射获取这个系统的属性状态,而原生的应用就不会有这个问题,并且原生应用也没有专门针对这个虚拟导航栏做适配代码。
        一半的程序员:先判断是否存在虚拟导航栏,然后设置不同的setTheme()主题就可以了

      本文标题:Android:这是一份Handler消息传递机制 的使用教程

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