Handler异步消息传递机制(二)在子线程中创建Handler

版权声明:本文为博主原创文章,不得随意转载,转载请注明出处!!! https://blog.csdn.net/YuDBL/article/details/85731034

声明:本教程不收取任何费用,欢迎转载,尊重作者劳动成果,不得用于商业用途,侵权必究!!!

目录

一、前言

二、在主线程中创建Handler

三、在子线程中创建Handler


上一篇文章我们讲到了Handler消息传递机制的最常见用法,我们在主线程创建了Handler对象,然后在新启动的线程创建一个Message对象,然后借助Handler对象发送出去,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,然后就可以进行UI更新操作了。想了解的可参考Handler异步消息传递机制(一)常用实现方式

一、前言

我们已经熟悉了Handler消息传递机制的最常见用法。依稀记得13年的某一天一个新来的Android同事,他说我运行程序出现bug了,报的错误信息为:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(),你知道怎么解决吗?因为我有收集bug问题解决方式的习惯,于是我找了找自己的笔记给他发了一个链接。然后没过3秒,又问你知道为什么吗?

当时有点懵,因为我完全没有印象。平时也不喜欢去记忆一些东西,除非是刚不久用到的东西才会有所印象吧,所以我的回答是:“ 很久了不是记得很清楚了”。当时感觉还是挺纳闷的,不就是new Hanlder发送消息吗?于是找了一些资料复习了一下。确实不过即使只是简单new一下,还是有不少地方需要注意的!

我们尝试在程序中创建两个Handler对象,一个在主线程中创建,一个在子线程中创建。

二、在主线程中创建Handler

详见上篇文章 Handler异步消息传递机制(一)常用实现方式 ,它是典型的在主线程中创建Handler的实例

三、在子线程中创建Handler

我们继续以文章 Handler异步消息传递机制(一)Handler常用实现方式 的demo为例,我们把主线程创建的Hanlder注释掉,然后挪到新启动的子线程,代码如下:

package com.luminal.handler_download;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;


public class MainActivity extends AppCompatActivity {
    private  TextView show_text;
    private String strMsg;
    private Handler handler;

    //在主线程中获取、处理消息
//    private Handler handler = new Handler() {
//        @Override
//        public void handleMessage(Message msg) {
//            switch (msg.what) {
//                case 1://下载成功
//                    strMsg = strMsg +"\n"+ "2、apk下载成功。。。开始自动安装下载好的apk!";
//                    show_text.setText(strMsg);
//                    break;
//                case 2://下载失败
//                    strMsg = strMsg +"\n"+ "apk下载失败!";
//                    show_text.setText(strMsg);
//                    break;
//
//                default:
//                    break;
//            }
//        }
//    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        show_text = (TextView) findViewById(R.id.show_text);

        downloadApkFile();

    }


    /**
     *  下载apk文件
     *  注:Android 6.0以上需要申请读写权限
     */
    private void downloadApkFile() {

        strMsg = "1、开始下载apk。。。";
        show_text.setText(strMsg);

        new Thread() {//在新启动的子线程,调用下载app的代码,并发送消息、反馈结果
            public void run() {

                handler = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        switch (msg.what) {
                            case 1://下载成功
                                strMsg = strMsg +"\n"+ "2、apk下载成功。。。开始自动安装下载好的apk!";
                                show_text.setText(strMsg);
                                break;
                            case 2://下载失败
                                strMsg = strMsg +"\n"+ "apk下载失败!";
                                show_text.setText(strMsg);
                                break;

                            default:
                                break;
                        }
                    }
                };


                DownLoadAppFile downLoadFile = new DownLoadAppFile();
                downLoadFile.download(null, handler, null);

            };
        }.start();
    }
}

然后运行程序,你会发现,在子线程中创建的Handler是会导致程序崩溃的,提示的错误信息如下:

   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)
        at com.luminal.handler_download.MainActivity$1$1.<init>(MainActivity.java:60)
        at com.luminal.handler_download.MainActivity$1.run(MainActivity.java:60)

报错信息为:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(),具体指向代码错误第60行,创建Handler的语句:handler = new Handler() 

英文直译下,说是不能在没有调用Looper.prepare() 的线程中创建Handler,那我们试试在线程中先调用一下Looper.prepare(),再创建Handler对象。

                Looper.prepare();
                handler = new Handler() {
                。。。。。。

然后再运行一下程序,果然这样就不会崩溃了,你会发现bug就这么神奇的解决了,但是这时候UI不能更新了!

那么为什么子线程不调用Looper.prepare()就创建Handler会报错呢?

 Handler异步消息传递机制(三)在主线程、子线程中创建Handler,源码(Android 9.0)解析

子线程调用了Looper.prepare()、创建Handler,以后UI能不能更新呢?

欲知故事如何请看下文整理分解,本故事不是虚构,如有雷同,纯属巧合,呵呵!

猜你喜欢

转载自blog.csdn.net/YuDBL/article/details/85731034