zoukankan      html  css  js  c++  java
  • Android Handler消息传递机制

    1. Handler消息传递机制初步认识:什么是Handler?
    handler通俗一点讲就是用来在各个线程之间发送数据的处理对象。在任何线程中,只要获得了另一个线程的handler,则可以通过 handler.sendMessage(message)方法向那个线程发送数据。基于这个机制,我们在处理多线程的时候可以新建一个thread,这个thread拥有UI线程中的一个handler。当thread处理完一些耗时的操作后通过传递过来的handler向UI线程发送数据,由UI线程去更新界面。
    主线程:运行所有UI组件,它通过一个消息队列来完成此任务。设备会将用户 的每项操作转换为消息,并将它们放入正在运行的消息队列中。主线程位于一个循环中,并处理每条消息。如果任何一个消息用时超过5秒,Android将抛出 ANR。所以一个任务用时超过5秒,应该在一个独立线程中完成它,或者延迟处理它,当主线程空闲下来再返回来处理它。

    2.常用类:(Handler、Looper、Message、MessageQueue)
    Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
    Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现 handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。Handler类的主要作用:(有两个主要作用)1)、在工作线程中发送消息;2)、在 主线程中获w/取、并处理消息。
    MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message串联起来的,等待Looper的抽取。
    Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。

    3.Handler、Looper、Message、MessageQueue之间的关系:

    • Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue;
    • 而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue;
    • 在一个线程中,只能有一个Looper和MessageQueue,但是可以有多个Handler,而且这些Handler可以共享一个Looper和MessageQueue;
    • Message被存放在 MessageQueue中,一个 MessageQueue中可以包含多个Message对象

    【备注:】
    Looper对象用来为一个线程开启一个消息循环,从而操作MessageQueue;
    默认情况下,Android创建的线程没有开启消息循环Looper,但是主线程例外。
    系统自动为主线程创建Looper对象,开启消息循环;
    所以主线程中使用new来创建Handler对象。而子线程中不能直接new来创建Handler对象就会异常。
    子线程中创建Handler对象,步骤如下:
    Looper.prepare();
    Handler handler = new Handler() {
    //handlemessage(){}
    }
    Looper.loop();

    4.Handler类中常用方法:
    (1) handleMessage() 用在主线程中,构造Handler对象时,重写handleMessage()方法。该方法根据工作线程返回的消息标识,来分别执行不同的操作。
    (2) sendEmptyMessage() 用在工作线程中,发送空消息。
    (3) sendMessage() 用在工作线程中,立即发送消息。

    5.Message消息类中常用属性:
    (1) arg1 用来存放整型数据
    (2) arg2 用来存放整型数据
    (3) obj 用来存放Object数据
    (4) what 用于指定用户自定义的消息代码,这样便于主线程接收后,根据消息代码不同而执行不同的相应操作。

    上一下Demo的示例代码:

    private Handler handler = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            text_main_info = (TextView) findViewById(R.id.text_main_info);
            pDialog = new ProgressDialog(MainActivity.this);
            pDialog.setMessage("Loading...");
            image_main = (ImageView) findViewById(R.id.image_main);
    
            // 主线程中的handler对象会处理工作线程中发送的Message。根据Message的不同编号进行相应的操作。
            handler = new Handler() {
                    public void handleMessage(android.os.Message msg) {
                            // 工作线程中要发送的信息全都被放到了Message对象中,也就是上面的参数msg中。要进行操作就要先取出msg中传递的数据。
                            switch (msg.what) {
                            case 0:
                                    // 工作线程发送what为0的信息代表线程开启了。主线程中相应的显示一个进度对话框
                                    pDialog.show();
                                    break;
                            case 1:
                                    // 工作线程发送what为1的信息代表要线程已经将需要的数据加载完毕。本案例中就需要将该数据获取到,显示到指定ImageView控件中即可。
                                    image_main.setImageBitmap((Bitmap) msg.obj);
                                    break;
                            case 2:
                                    // 工作线程发送what为2的信息代表工作线程结束。本案例中,主线程只需要将进度对话框取消即可。
                                    pDialog.dismiss();
                                    break;
                            }
                    }
            };
    
            new Thread(new Runnable() {
                    @Override
                    public void run() {
                            // 当工作线程刚开始启动时,希望显示进度对话框,此时让handler发送一个空信息即可。
                            // 当发送这个信息后,主线程会回调handler对象中的handleMessage()方法。handleMessage()方法中
                            // 会根据message的what种类来执行不同的操作。
                            handler.sendEmptyMessage(0);
    
                            // 工作线程执行访问网络,加载网络图片的任务。
                            byte[] data = HttpClientHelper.loadByteFromURL(urlString);
                            // 工作线程将网络访问获取的字节数组生成Bitmap位图。
                            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
                                            data.length);
                            // 工作线程将要发送给主线程的信息都放到一个Message信息对象中。
                            // 而Message对象的构建建议使用obtain()方法生成,而不建议用new来生成。
                            Message msgMessage = Message.obtain();
                            // 将需要传递到主线程的数据放到Message对象的obj属性中,以便于传递到主线程。
                            msgMessage.obj = bitmap;
                            // Message对象的what属性是为了区别信息种类,而方便主线程中根据这些类别做相应的操作。
                            msgMessage.what = 1;
                            // handler对象携带着Message中的数据返回到主线程
                            handler.sendMessage(msgMessage);
    
                            // handler再发出一个空信息,目的是告诉主线程工作线程的任务执行完毕。一般主线程会接收到这个消息后,
                            // 将进度对话框关闭
                            handler.sendEmptyMessage(2);
                    }
            }).start();
    }
  • 相关阅读:
    [译文] 实体与值对象到底是不是一回事?
    实现 WebApi 自托管服务宿主于 WinForms 及其交互
    [译文] C# 8 已成旧闻, 向前, 抵达 C# 9!
    [译文] 为什么你在 C# 里总是应该使用 "var" 关键字
    通过设置iis在局域网中访问网页
    windows 10 安装使用kafka
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 4) 整合Polly实现瞬时故障处理
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 3) 使用Handler实现传出请求中间件
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 2) 定义命名化和类型化的客户端
    Asp.net Core 2.0 OpenId Connect Handler缺失Claims?
  • 原文地址:https://www.cnblogs.com/upwgh/p/5901124.html
Copyright © 2011-2022 走看看