Android基础知识总结_Handler

目录

在这里插入图片描述

什么是Handler

Handler是Android给我们提供的一套消息处理机制,平常我们经常用Handler就是将子线程的数据传递给主线程,其实,熟悉Handler原理之后我们知道,Handler不仅仅能将子线程的数据传递给主线程,它能实现任意两个线程的数据传递。

Handler的使用方法

在这里插入图片描述首先看一下Handler最常规的使用方式:

private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MESSAGE_WHAT:
                    Log.d(TAG, "main thread receiver message: " + ((String) msg.obj));
                    break;
            }
        }
    };
    
    private void sendMessageToMainThreadByWorkThread() {
        new Thread(){
            @Override
            public void run() {
                Message message = mHandler.obtainMessage(MESSAGE_WHAT);
                message.obj = "你好,我是子线程";
                mHandler.sendMessage(message);
            }
        }.start();
    }
    /*
    * 通常我们在主线程中创建一个Handler,
    * 然后重写该Handler的handlerMessage方法,可以看到该方法传入了一个参数Message,
    * 该参数就是我们从其他线程传递过来的信息。
    *
    * 我们在来看下子线程中如何传递的信息,子线程通过Handler的obtainMessage()方法获取到一个Message实例,
    * 我们来看看Message的几个属性:
    * Message.what------------------>用来标识信息的int值,通过该值主线程能判断出来自不同地方的信息来源
    * Message.arg1/Message.arg2----->Message初始定义的用来传递int类型值的两个变量
    * Message.obj------------------->用来传递任何实例化对象
    * 最后通过sendMessage将Message发送出去。
    * Handler所在的线程通过handlerMessage方法就能收到具体的信息了,如何判断信息的来源呢?可以通过what值来判断.
    */

首先我们在主线程中创建一个Handler,
然后重写该Handler的handlerMessage方法,可以看到该方法传入了一个参数Message,
该参数就是我们从其他线程传递过来的信息。
子线程:
子线程通过Handler的obtainMessage()方法获取到一个Message实例,向Message中可以传入任何实例化对象(需要发送的内容)最后通过sendMessage将Message发送出去。
Handler所在的线程通过handlerMessage方法就能收到具体的信息了.


上面提到Handler不仅仅是能过将子线程的数据发送给主线程,它适用于任意两个线程之间的通信。
下面我们来看下两个子线程之间如何进行通信的。
就按照正常逻辑在一个线程创建Handler,另外一个线程通过持有该Handler的引用调用sendMessage发送消息就可以了!
接下来通过代码实现以下:

private Handler handler;
    private void handlerDemoByTwoWorkThread() {
        Thread hanMeiMeiThread = new Thread() {
            @Override
            public void run() {
//                Looper.prepare();
                handler = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        Log.d(TAG, "hanMeiMei receiver message: " + ((String) msg.obj));
                        Toast.makeText(MainActivity.this, ((String) msg.obj), Toast.LENGTH_SHORT).show();
                    }
                };
//                Looper.loop();
            }
        };
        Thread liLeiThread = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message message = handler.obtainMessage();
                message.obj = "Hi MeiMei";
                handler.sendMessage(message);
            }
        };
        hanMeiMeiThread.setName("韩梅梅 Thread");
        hanMeiMeiThread.start();
        liLeiThread.setName("李雷 Thread");
        liLeiThread.start();

        /*
        * 搞定,我们创建了两个Thread,liLeiThread和hanMeiMeiThread两个线程,很熟悉的名字啊!
        * 跟之前的代码没太大区别hanMeiMeiThread创建了Handler,liLeiThread通过Handler发送了消息。
        * 只不过此处我们只发送一个消息,所以没有使用what来进行标记
        * 运行看看,我们的李雷能拨通梅梅吗?
        * 啊哦,出错了
        * 05-13 17:08:17.709 20673-20739/? E/AndroidRuntime: FATAL EXCEPTION: 韩梅梅 Thread
                                                   Process: design.wang.com.designpatterns, PID: 20673
                                                   java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
                                                       at android.os.Handler.<init>(Handler.java:200)
                                                       at android.os.Handler.<init>(Handler.java:114)
        *Can't create handler inside thread that has not called Looper.prepare()
        * -----------》它说我们创建的handler没有调用Looper.prepare();
        * 好的,我们在实例化Handler之前调用下该方法,看一下。加上是不是没有报错了呢。
        * 等等,虽然没有报错,但是hanMeiMeiThread也没有接到消息啊,消息呢?别急。
        * 我们在Handler实例化之后加上Looper.loop();看一看,运行一下,是不是收到消息了呢。
        * 这是为什么呢?
        * 接下来我们就去看看Handler是怎么实现的发消息呢,弄清楚了原理,这里的原因也就明白了。
        */

    }

通过代码实现后运行程序,会发现抛出异常了,

Can't create handler inside thread that has not called Looper.prepare()

提示我们创建的handler没有调用Looper.prepare();
那么我们在实例化Handler之前调用下该方法,看一下还会不会报错.
运行后发现并没有报错,但是发出去的消息并没有被接收到,
在Handler实例化之后加上Looper.loop();看一看,运行一下,是不是收到消息了呢。
既然加上了Looper.loop();就可以收到消息了,那是不是就可以说Looper.loop()就是用来发送消息的呢?
我们可以去源码中看一下我们抛出的异常的原因和为什么在子线程中要多了Looper,并且验证下我们的猜想.
首先我们来看下,为什么在子线程里实例化的时候不调用Looper.prepare()就会报错呢?

mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }

我们找到Handler构造函数里抛出上文异常的地方,可以看到,是由于mLooper对象为空才抛出的该异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值