一般我们都把Toast当做一个UI控件在主线程显示。但是有时候非想在子线程中显示Toast,就会使用Handler切换到主线程显示。

但是子线程中真的不能直接显示Toast吗?

答案是:当然可以。

那应该怎么操作呢?在当前线程中先初始化一个Looper即可!

Looper.prepare();
Toast.makeText(getBaseContext(), "text", Toast.LENGTH_LONG).show();
Looper.loop();

为什么在子线程中使用Toast需要初始一个Looper呢? 我们看看源代码:

  public static Toast makeText(Context context, CharSequence text, @Duration int duration) {
        return makeText(context, null, text, duration);
    }

public static Toast makeText(@NonNull Context context, @Nullable Looper looper,
            @NonNull CharSequence text, @Duration int duration) {
        Toast result = new Toast(context, looper);
        ...
        return result;
    }

以上是我们使用Toast时调用的静态方法,可以看到第二个方法有个参数Looper,虽然我们平时用的时候都传入的是null,那这个Looper究竟有什么用呢?我们看看Toast的构造函数:

  public Toast(@NonNull Context context, @Nullable Looper looper) {
        mContext = context;
        mTN = new TN(context.getPackageName(), looper);
    }

可以看出这个Looper其实是TN在用,我们看看它的构造函数:

     TN(String packageName, @Nullable Looper looper) {
            if (looper == null) {
                // Use Looper.myLooper() if looper is not specified.
                looper = Looper.myLooper();
                if (looper == null) {
                    throw new RuntimeException(
                            "Can't toast on a thread that has not called Looper.prepare()");
                }
            }

        }

以上代码有简化。可以看出当Looper为null的时候,会通过Looper.myLooper获取一个当前的Looper。我们知道在主线程中系统已经为我们初始化了一个mainLooper,所以我们一般不用管。但是当我们子线程中如果没有初始化Looper,这里调用Looper.myLooper就获取不到一个Looper,则会抛出异常。所以当我们在子线程中使用Toast,使用Looper.prepare()方法初始化一个Looper并用Looper.loop()让它启动起来即可。

所以我们可以封装一个可以在任何线程使用的Toast。

 private static Toast toast = null;
    public static void showToast(Context context, String text) {
        Looper myLooper = Looper.myLooper();
        if (myLooper == null) {
            Looper.prepare();
            myLooper = Looper.myLooper();
        }

        if (toast == null) {
            toast = Toast.makeText(context, text, Toast.LENGTH_LONG);
            toast.setGravity(Gravity.CENTER, 0, 0);
        }
        toast.show();
        if ( myLooper != null) {
            Looper.loop();
            myLooper.quit();
        }
    }

我们初始化Toast之前先判断当前线程的looper是否为空,为空则初始化一个新的myLooper,然后在调用Toast的show方法之后让looper启动起来即可。因为Looper的loop()方法是无限循环的,为了防止Looper阻塞线程,导致内存泄漏应该及时退出Looper。

Android进阶:六、在子线程中直接使用 Toast 及其原理的更多相关文章

  1. Android利用Looper在子线程中改变UI

    MainActivity如下: package cn.testlooper; import android.app.Activity; import android.os.Bundle; import ...

  2. Android开发之在子线程中使用Toast

    在子线程中使用Toast的时候,出现Force close. 错误提示:Can't create handler inside thread that has not called Looper.pr ...

  3. Android在子线程中更新UI(二)

    MainActivity如下: package cc.testui2; import android.os.Bundle; import android.view.View; import andro ...

  4. Android在子线程中更新UI(一)

    MainActivity如下: package cc.testui1; import android.os.Bundle; import android.os.Handler; import andr ...

  5. Android开发UI之在子线程中更新UI

    转自第一行代码-Android Android是不允许在子线程中进行UI操作的.在子线程中去执行耗时操作,然后根据任务的执行结果来更新相应的UI控件,需要用到Android提供的异步消息处理机制. 代 ...

  6. 【第三篇】学习 android 事件总线androidEventbus之发布事件,子线程中接收

    发送和接收消息的方式类似其他的发送和接收消息的事件总线一样,不同的点或者应该注意的地方: 1,比如在子线程构造方法里面进行实现总线的注册操作: 2,要想子线程中接收消息的功能执行,必须启动线程. 3, ...

  7. 老问题:Android子线程中更新UI的3种方法

    在Android项目中经常有碰到这样的问题,在子线程中完成耗时操作之后要更新UI,下面就自己经历的一些项目总结一下更新的方法: 方法一:用Handler 1.主线程中定义Handler: Handle ...

  8. android 不能在子线程中更新ui的讨论和分析

    问题描写叙述 做过android开发基本都遇见过 ViewRootImpl$CalledFromWrongThreadException,上网一查,得到结果基本都是仅仅能在主线程中更改 ui.子线程要 ...

  9. android UI 操作 不要在子线程中操作UI

    不管是android ,还是 ios ,请不要在子线程中操作UI,有时有些崩溃,从报错上看不出什么原因,就有可能是子线程操作了UI:切记,切记! 请放在主线程例: activity.runOnUiTh ...

随机推荐

  1. 基础概念【softmax|normalizatoin|standardization】

    目录 一.softmax 二.normalization 三.standardization 一.softmax 为什么使用softmax,不用normalization? “max” because ...

  2. MapReduce-TextInputFormat 切片机制

    MapReduce 默认使用 TextInputFormat 进行切片,其机制如下 (1)简单地按照文件的内容长度进行切片 (2)切片大小,默认等于Block大小,可单独设置 (3)切片时不考虑数据集 ...

  3. JetBrain server certificate is not trusted 弹出框

    To get rid of the pop up message go to below location and click on Accept non-trusted certificates a ...

  4. react native 安卓home返回键页面刷新

    import { withNavigationFocus } from 'react-navigation'; class Warngreete extends React.Component { c ...

  5. http升级https的时候,遇到一个问题

    问题: Mixed Content: The page at 'https://api.xxxx.com/test' was loaded over HTTPS, but requested an i ...

  6. awk和sed截取nginx和tomcat时间段日志

    1 nginx日志截取示例 日志路径:/usr/local/nginx/logs, 截取access.log中2019年3月24日17点00~02之间的日志: 写法1: cat access.log ...

  7. Springboot项目打包后的页面丢失问题(thymeleaf报错)

    遇到的问题目前找到两种: 返回视图路径以/开头,例如 /test/hello 在thymeleaf页面中,引入的页面以/开头,例如:<footer th:replace="/index ...

  8. python制作串口工具

    # coding:utf-8import timeimport serialimport stringimport binasciiimport linecache FilePath="G: ...

  9. (转)Java语法----Java中equals和==的区别

    转载地址:https://www.cnblogs.com/smyhvae/p/3929585.html 一.java当中的数据类型和“==”的含义: 基本数据类型(也称原始数据类型) :byte,sh ...

  10. 逆向 make 打包错误解决方案 make: *** [internal-package] Error 2

    修改deb.mk文件第6行的压缩方式为gzip vim $THEOS/makefiles/package/deb.mk _THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?= ...