Android进阶:六、在子线程中直接使用 Toast 及其原理

发布时间:2019-06-03 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Android进阶:六、在子线程中直接使用 Toast 及其原理脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
最近因为个人原因,很久没有更文章,感谢关注的小伙伴,望谅解!

一般我们都把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在用,我们看看它的构造函数:

@H_715_126@ 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 t@R_304_2570@ 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。

写在最后
如果你想了解现在市场的行情,如果你想和一群开发经验丰富的人交流学习,如果你想更快的成长,如果你想有目标有方向的去进阶,欢迎加入我的合作交流群925019412
在这里你有一批志同道合的伙伴一起交流学技术,有好的资源资料一起分享!flutter—性能优化—移动架构—资深UI工程师 —NDK相关专业人员和视频教学资料
交流群925019412

脚本宝典总结

以上是脚本宝典为你收集整理的Android进阶:六、在子线程中直接使用 Toast 及其原理全部内容,希望文章能够帮你解决Android进阶:六、在子线程中直接使用 Toast 及其原理所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。