Android 吐司框架,专治 Toast 各种疑难杂症

Android 吐司框架,专治 Toast 各种疑难杂症

项目地址:传送门

集成步骤

  • 如果你的项目 Gradle 配置是在 7.0 以下,需要在 build.gradle 文件中加入

allprojects {
    repositories {        // JitPack 远程仓库:https://jitpack.io
        maven { url 'https://jitpack.io' }
    }
}
  • 如果你的 Gradle 配置是 7.0 及以上,则需要在 settings.gradle 文件中加入

dependencyResolutionManagement {
    repositories {        // JitPack 远程仓库:https://jitpack.io
        maven { url 'https://jitpack.io' }
    }
}
  • 配置完远程仓库后,在项目 app 模块下的 build.gradle 文件中加入远程依赖

android {    // 支持 JDK 1.8
    compileOptions {
        targetCompatibility JavaVersion.VERSION_1_8
        sourceCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {    // 吐司框架:https://github.com/getActivity/ToastUtils
    implementation 'com.github.getActivity:ToastUtils:10.5'}

初始化框架

public class XxxApplication extends Application {    @Override
    public void onCreate() {        super.onCreate();        // 初始化 Toast 框架
        ToastUtils.init(this);
    }
}

框架 API 介绍

// 显示 ToastToastUtils.show(CharSequence text);
ToastUtils.show(int id);// debug 模式下显示 ToastToastUtils.debugShow(int id);
ToastUtils.debugShow(CharSequence text);// 延迟显示 ToastToastUtils.delayedShow(int id, long delayMillis);
ToastUtils.delayedShow(CharSequence text, long delayMillis);// 取消 ToastToastUtils.cancel();// 设置 Toast 布局ToastUtils.setView(int id);// 设置 Toast 布局样式ToastUtils.setStyle(IToastStyle<?> style);// 获取 Toast 布局样式ToastUtils.getStyle()// 判断当前框架是否已经初始化ToastUtils.isInit();// 设置 Toast 策略ToastUtils.setStrategy(IToastStrategy strategy);// 获取 Toast 策略ToastUtils.getStrategy();// 设置 Toast 重心和偏移ToastUtils.setGravity(int gravity);
ToastUtils.setGravity(int gravity, int xOffset, int yOffset);// 设置 Toast 拦截器ToastUtils.setInterceptor(IToastInterceptor interceptor);// 获取 Toast 拦截器ToastUtils.getInterceptor();
  • 如果你需要对 Toast 的进行深度定制化,可以使用以下方式

ToastUtils.init(this, new ToastStrategy() {    @Override
    public IToast createToast(Application application) {
        IToast toast = super.createToast(application);        if (toast instanceof CustomToast) {
            CustomToast customToast = ((CustomToast) toast);            // 设置 Toast 动画效果
            customToast.setAnimationsId(R.anim.xxx);            // 设置短 Toast 的显示时长(默认是 2000 毫秒)
            customToast.setShortDuration(1000);            // 设置长 Toast 的显示时长(默认是 3500 毫秒)
            customToast.setLongDuration(5000);
        }        return toast;
    }
});
  • 这种方式的缺点是只有应用在前台的情况下才会生效,这是因为前台的 Toast 是用框架实现的,本质上是一个 WindowManager,优点是非常灵活,不受原生 Toast 机制限制,缺点是无法在后台的情况下显示;而后台的 Toast 是用系统来实现的,优点是能在后台的情况下显示,缺点是局限性非常大,无法做太深的定制化;而框架正是利用了两种方式的优缺点进行了互补。

温馨提示:框架意在解决一些常规的 Toast 需求,如果是有一些特殊的定制化需求请配搭 XToast 悬浮窗框架使用

不同 Toast 框架之间的对比

功能或细节ToastUtilsAndroidUtilCodeToasty
对应版本10.51.30.61.5.0
issues 数


aar 包大小29 KB500 KB50 KB
调用代码定位
支持在子线程中调用显示
支持全局设置统一 Toast 样式
处理 Toast 在 Android 7.1 崩溃的问题
兼容通知栏权限关闭后 Toast 显示不出来的问题
适配 Android 11 不能在后台显示 Toast 的问题

调用代码定位功能介绍

  • 框架会在日志打印中输出在 Toast 调用的代码位置,这样开发者可以直接通过点击 Log 来定位是在哪个类哪行代码调用的,这样可以极大提升我们排查问题的效率,特别是 Toast 的内容是由后台返回的情况下,我相信没有任何一个人会拒绝这样的功能。

Toast 在 Android 7.1 崩溃的问题介绍

Toast 在 Android 7.1 崩溃排查及修复

  • 这个问题是由于 Android 7.1 加入 WindowToken 校验机制导致的,而这个 WindowToken 是 NotificationManagerService 生成的,这个 WindowToken 是存在一定时效性的,而当应用的主线程被阻塞时,WindowManager 在 addView 时会对 WindowToken 进行校验,但是 WindowToken 已经过期了,这个时候 addView 就会抛出异常。

  • 谷歌在 Android 8.0 就修复了这个问题,修复方式十分简单粗暴,就是直接捕获这个异常,而框架的修复思路跟谷歌类似,只不过修复方式不太一样,因为框架无法直接修改系统源码,所以是直接通过 Hook 的方式对异常进行捕获。

通知栏权限关闭后 Toast 显示不出来的问题介绍

Toast通知栏权限填坑指南

  • 这个问题的出现是因为原生 Toast 的显示要通过 NMS(NotificationManagerService) 才会 addView 到 Window 上面,而在 NMS 中有一个 static final boolean ENABLE_BLOCKED_TOASTS = true 的字段,当这个常量值为 true 时,会触发 NMS 对应用通知栏权限的检查,如果没有通知栏权限,那么这个 Toast 将会被 NMS 所拦截,并输出 Suppressing toast from package 日志信息,而小米手机没有这个问题是因为它是将 ENABLE_BLOCKED_TOASTS 字段值修改成 false,所以就不会触发对通知栏权限的检查,另外我为什么会知道有这个事情?因为我曾经和一名 MIUI 工程师一起确认过这个事情。

  • 框架处理这个问题的方式有两种,先判断当前应用是否处于前台状态,如果是则使用自定义的 WindowManager 代替 Toast 来显示,如果当前应用处于后台状态,则会通过 Hook Toast 中的 INotificationManager 接口,将 enqueueToast 方法传递的包名参数修改成 android 来欺骗 NotificationManagerService,因为 NotificationManagerService 已经将 android 包名的应用纳入白名单,会自动放行,需要注意的是,这种方式在 Android 10 上面已经失效了,已经被系统纳入反射黑名单,但是好消息是,通过查看和对比 NotificationManagerService 源码发现,这个问题(关闭通知栏权限后无法在前台弹 Toast 的问题)已经在 Android 10.0 的版本上面被修复了,所以框架只在 Android 9.0 及以下版本并且在关闭了通知栏权限的情况下才去 Hook INotificationManager,另外我还找到了官方关于这块的代码提交记录:Always allow toasts from foreground apps,大家可以感兴趣可以看看,还有一个问题,如果你想在 Android 10 之后仍然能在后台显示 Toast,请保证应用的通知栏权限或者悬浮窗权限处于开启的状态。

Android 11 不能在后台显示 Toast 的问题介绍

  • 当我们将 targetSdkVersion 改成 30 及以上的版本时,会发现一个问题,如果应用处于后台进程的情况下,而恰好我们的应用 Toast 样式是经过定制的,那么在这些情况下调用 Toast 的 show 方法会惊奇的发现,Toast 没有显示出来,请注意这个问题不是 Bug,而是 Android 11 禁止了这种行为,在 Toast 官方文档 中也有注明,不建议对 Toast 的样式做定制化,并且还对 Toast.setView 方法进行了标记过时处理。

  • 那么我们如何解决这一问题呢?难道真的不能用自定义样式的 Toast 了?我的答案是:不,凡事不能一刀切,谷歌只说不能在后台显示自定义的 Toast,并不能代表不能在前台那么做,框架的适配思路是,在 Android 11 的情况下,会先判断当前应用是处于前台还是后台,如果是在前台的情况下就显示自定义样式的 Toast,如果是在后台的情况下就显示系统样式的 Toast(通过舍弃自定义样式来保证 Toast 能够正常显示出来),这样既能符合 Android 11 要求,同时又能将定制化 Toast 的权益最大化。

  • 值得注意的是:ToastUtils 是目前同类框架第一款也是唯一一款适配 Android 11 这一特性的框架。

框架亮点

  • 一马当先:首款适配 Android 11 的吐司框架,使用者无需关心适配过程

  • 无需权限:不管有没有授予通知栏权限都不影响吐司的弹出

  • 兼容性强:处理原生 Toast 在 Android 7.1 产生崩溃的历史遗留问题

  • 功能强大:不分主次线程都可以弹出Toast,自动识别资源 id 和 int 类型

  • 使用简单:只需传入文本,会自动根据文本长度决定吐司显示的时长

  • 性能最佳:使用懒加载模式,只在显示时创建 Toast,不占用 Application 启动时间

  • 体验最佳:显示下一个 Toast 会取消上一个 Toast 的显示,真正做到即显即示

  • 全局统一:可以在 Application 中初始化 Toast 样式,达到一劳永逸的效果

如何替换项目中已有的原生 Toast

  • 在项目中右击弹出菜单,Replace in path,勾选 Regex 选项,点击替换

Toast\.makeText\([^,]+,\s*(.+),\s*[^,]+\)\.show\(\)
ToastUtils.show($1)
  • 对导包进行替换

import android.widget.Toast
import com.hjq.toast.ToastUtils
  • 再全局搜索,手动更换一些没有替换成功的

Toast.makeText
new Toast


来源: 互联网
本文观点不代表码客-全球程序员交流社区立场,不承担法律责任,文章及观点也不构成任何投资意见。

赞 ()

相关推荐

  • 置顶 开发项目接单群,免费入群了

    无论你是Android、ios、java、php,或者你是产品经理、老板,都可以免费入群接单或者发布项目,全程不收取任何费用。

    2025年02月21日 15点27分
  • 鸿蒙Next-AttributeModifier结合@Styles和@Extend深度解析使用

    声明式语法引入了@Styles和@Extend两个装饰器,可以解决复用相同自定义样式的问题,但是存在以下受限场景:

    2025年03月03日 15点40分
  • ConstraintLayout之layout_constraintDimensionRatio属性详解

    layout_constraintDimensionRatio 是 ConstraintLayout 提供的一个强大功能,它可以让 View 按照固定的宽高比例自适应尺寸。使用这个属性,可以在 ConstraintLayout 中根据已知的宽度或高度,自动计算另一个维度,确保 View 保持特定的宽高比。

    2025年03月03日 15点39分
  • Android事件分发时,你浓眉大眼的onTouch()竟然没有执行?

    在开发需求时,有这么一个场景:Activity中有一个ViewGroup作为Parent,ViewGroup里面又有一个Webview作为Child。当一进入页面时,系统输入法自动弹起,而在点击Parent区域时,需要收起系统输入法。背景介绍完毕,当时的第一想法就是通过Parent设置setOnTouchListener,然后在onTouch()回调中来实现:

    2025年03月02日 15点10分
  • Android SDK封装与发布实战指南

    Android SDK封装与发布实战指南

    2025年03月02日 15点05分
  • 鸿蒙Next开发-添加水印以及点击穿透设置

    在鸿蒙Next中,为App全局添加水印可以通过以下方式实现,其中通过窗口添加水印是一种常见且高效的方式。以下是具体方案和实现细节:

    2025年02月26日 23点15分
  • 鸿蒙Next开发-普通函数和箭头函数 this指向的区别以及对UI刷新的影响

    鸿蒙Next开发-普通函数和箭头函数 this指向的区别以及对UI刷新的影响

    2025年02月26日 23点14分
  • 深入探索ArkUI @Builder与@BuilderParam的进阶应用

    在ArkUI的组件化开发体系中,@Builder和@BuilderParam这对装饰器组合扮演着UI模块化的重要角色。二者的差异与配合体现了声明式UI的核心思想:

    2025年02月26日 23点12分
  • Deepseek推荐:Android 开发者需要掌握的系统知识大纲

    一、操作系统基础1. Linux 内核机制内容介绍 Android 基于 Linux 内核,核心机制包括进程管理、内存管理、文件系统、Binder 驱动等。

    2025年02月26日 23点09分
  • Android App 厂商角标适配

    本篇介绍一下笔者在维护IM应用时,设置App角标的相关经验。同时这里设置角标都是基于系统厂商的Launcher,没有适配三方的Launcher应用,因为我们统计下来发现近些年使用三方Launcher应用比较少了,大部分用户还是以系统Launcher为主。所在在我们的项目中,主要是适配各个厂商。

    2025年02月26日 23点07分
  • 鸿蒙Next-方法装饰器以及防抖方法注解实现

    以下是关于 鸿蒙Next(HarmonyOS NEXT)中 MethodDecorator 的详细介绍及使用指南,结合了多个技术来源的实践总结:

    2025年02月26日 22点58分
  • DevEco Studio常用快捷键以及如何跟AndroidStudio的保持同步

    DevEco Studio是华为推出的用于开发HarmonyOS应用的集成开发环境,它提供了丰富的快捷键以提高开发效率,以下为你详细介绍不同操作场景下的常用快捷键:

    2025年02月26日 22点56分
  • Android | 利用ItemDecoration绘制RecyclerView分割线

    RecyclerView.ItemDecoration 是 Android 提供的一种扩展机制,用于为 RecyclerView 的每个子项(Item)添加装饰(Decoration)。它通常用于绘制分割线、边距、背景等,目的是增强 RecyclerView 的显示效果。

    2025年02月26日 22点52分
  • Android 布局优化:利用 ViewStub 和 Merge 提升性能

    提升界面渲染性能是一个至关重要的任务,尤其是在应用启动时,渲染界面需要快速且流畅。为了优化 UI 渲染速度,Android 提供了许多工具,其中 ViewStub 和 Merge 标签是非常有效的布局优化手段。通过合理使用这两者,可以延迟加载不必要的视图、减少布局的嵌套层级,从而加速应用的启动和运行。

    2025年02月26日 22点47分
  • 玩转 ImageView.ScaleType:图片的缩放与裁剪技巧

    ImageView 是最常用的控件之一,它用于展示各种类型的图片。为了能够根据需求调整图片的显示效果,Android 提供了 ImageView.ScaleType 枚举,它可以灵活地控制图片如何适应 ImageView 的尺寸。本文将探讨 ImageView.ScaleType 的不同选项、使用场景及其实现技巧。

    2025年02月26日 22点45分
  • Android加快你的编译速度

    工欲善其事,必先利其器。如果每次运行项目都要花费5-10分钟,那人的心态都要崩了。

    2025年02月25日 15点40分

发表回复

评论列表

点击查看更多

    联系我们

    在线咨询: QQ交谈

    微信:dxmcpjl

    邮件:1529097251#qq.com

    工作时间:周一至周五,9:30-18:30,节假日休息

    微信