Skip to content

Commit 0541c55

Browse files
committed
优化类名命名及代码注释
优化及抽取 Toast 创建的策略 优化匹配原生 Toast 的正则表达式
1 parent a46bfff commit 0541c55

File tree

11 files changed

+169
-147
lines changed

11 files changed

+169
-147
lines changed

README.md

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,69 +6,77 @@
66
77
> 已投入公司项目多时,没有任何毛病,可胜任任何需求,[点击此处下载Demo](ToastUtils.apk)
88
9-
> 想了解实现原理的可以点击此链接查看:[ToastUtils](https://github.com/getActivity/ToastUtils/blob/master/library/src/main/java/com/hjq/toast/ToastUtils.java) 源码
9+
> 想了解实现原理的可以点击此链接查看:[ToastUtils](library/src/main/java/com/hjq/toast/ToastUtils.java) 源码
1010
1111
![](ToastUtils.gif)
1212

1313
#### 本框架意在解决一些常见需求,如果是有一些极端的需求推荐使用 [XToast](https://github.com/getActivity/XToast)
1414

1515
#### 集成步骤
1616

17-
dependencies {
18-
implementation 'com.hjq:toast:8.6'
19-
}
17+
```groovy
18+
dependencies {
19+
implementation 'com.hjq:toast:8.8'
20+
}
21+
```
2022

2123
#### 初始化 Toast
2224

23-
// 在 Application 中初始化
24-
ToastUtils.init(this);
25+
```java
26+
// 在 Application 中初始化
27+
ToastUtils.init(this);
28+
```
2529

2630
#### 显示 Toast
2731

28-
ToastUtils.show("我是吐司");
32+
```java
33+
ToastUtils.show("我是吐司");
34+
```
2935

3036
#### 其他 API
3137

32-
// 设置Toast布局
33-
ToastUtils.setView();
38+
```java
39+
// 设置Toast布局
40+
ToastUtils.setView();
3441

35-
// 设置吐司重心
36-
ToastUtils.setGravity();
42+
// 设置吐司重心
43+
ToastUtils.setGravity();
3744

38-
// 获取Toast对象
39-
ToastUtils.getToast();
45+
// 获取Toast对象
46+
ToastUtils.getToast();
47+
```
4048

4149
#### 自定义Toast样式
4250

43-
> 如果对Toast的默认样式不满意,可以在Application初始化样式,具体可参考[ToastBlackStyle](https://github.com/getActivity/ToastUtils/blob/master/library/src/main/java/com/hjq/toast/style/ToastBlackStyle.java)类的实现
51+
> 如果对Toast的默认样式不满意,可以在Application初始化样式,具体可参考[ToastBlackStyle](library/src/main/java/com/hjq/toast/style/ToastBlackStyle.java)类的实现
4452
45-
ToastUtils.initStyle(new IToastStyle());
46-
47-
#### 混淆规则
48-
49-
-keep class com.hjq.toast.** {*;}
53+
```java
54+
ToastUtils.initStyle(new IToastStyle());
55+
```
5056

5157
#### 框架亮点
5258

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

55-
* 功能强大:不分主次线程都可以弹出Toast,自动区分资源id和int类型
61+
* 兼容性强:处理原生 Toast 在 Android 7.1 产生崩溃的历史遗留问题
62+
63+
* 功能强大:不分主次线程都可以弹出Toast,自动区分资源 id 和 int 类型
5664

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

59-
* 性能最佳:单例吐司,整个Toast只有一个TextView,并且通过代码创建
67+
* 性能最佳:单例吐司,整个 Toast 只有一个 TextView,并且通过代码创建
6068

61-
* 体验最优:限制Toast短时间内弹出的次数,避免频繁弹出造成不良的用户体验
69+
* 体验最优:限制 Toast 短时间内弹出的次数,避免频繁弹出造成不良的用户体验
6270

63-
* 支持多种样式:默认为黑色样式,夜间模式可使用白色样式,还有仿QQ吐司样式
71+
* 支持多种样式:默认为黑色样式,夜间模式可使用白色样式,还有仿 QQ 吐司样式
6472

6573
* 支持自定义样式:吐司(背景、圆角、重心、偏移),文字(大小、颜色、边距)
6674

67-
* 支持自定义扩展:支持获取ToastUtils中的Toast对象,支持重新自定义Toast布局
75+
* 支持自定义扩展:支持获取 ToastUtils 中的 Toast 对象,支持重新自定义 Toast 布局
6876

69-
* 支持全局配置样式:可以在Application中初始化Toast样式,达到一劳永逸的效果
77+
* 支持全局配置样式:可以在 Application 中初始化 Toast 样式,达到一劳永逸的效果
7078

71-
* 框架兼容性良好:本框架不依赖任何第三方库,支持 Eclipse 和 Studio 的集成使用
79+
* 已适配 Android R:Android 11 之后不能弹出自定义样式的 Toast,框架针对这种情况进行了适配
7280

7381
#### 关于通知栏权限
7482

@@ -90,23 +98,37 @@
9098

9199
> 右击项目,Replace in path,勾选 Regex 选项
92100
93-
Toast\.makeText\([^,]+,\s(.+{1}),\s[^,]+\)\.show\(\);
101+
```java
102+
Toast\.makeText\([^,]+,\s*(.+{1}),\s*[^,]+\)\.show\(\)
103+
```
94104

95105
> 替换使用
96106
97-
ToastUtils.show($1);
107+
```java
108+
ToastUtils.show($1)
109+
```
98110

99111
> 包名替换
100112
101-
import android.widget.Toast;
113+
```java
114+
import android.widget.Toast
115+
```
102116

103117
---
104118

105-
import com.hjq.toast.ToastUtils;
119+
```java
120+
import com.hjq.toast.ToastUtils
121+
```
122+
123+
> 再全局搜索,手动更换一些没有替换成功的
124+
125+
```java
126+
Toast.makeText
127+
```
106128

107129
#### 作者的其他开源项目
108130

109-
* 架构工程[AndroidProject](https://github.com/getActivity/AndroidProject)
131+
* 安卓架构[AndroidProject](https://github.com/getActivity/AndroidProject)
110132

111133
* 网络框架:[EasyHttp](https://github.com/getActivity/EasyHttp)
112134

ToastUtils.apk

443 KB
Binary file not shown.

app/build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ android {
77
applicationId "com.hjq.toast.demo"
88
minSdkVersion 14
99
targetSdkVersion 30
10-
versionCode 86
11-
versionName "8.6"
10+
versionCode 88
11+
versionName "8.8"
1212
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
1313
}
1414
buildTypes {
@@ -22,10 +22,10 @@ android {
2222
dependencies {
2323
implementation fileTree(include: ['*.jar'], dir: 'libs')
2424
implementation project(':library')
25-
implementation 'androidx.appcompat:appcompat:1.3.0-alpha01'
26-
implementation 'com.google.android.material:material:1.3.0-alpha01'
25+
implementation 'androidx.appcompat:appcompat:1.3.0-alpha02'
26+
implementation 'com.google.android.material:material:1.3.0-alpha02'
2727
// 标题栏:https://github.com/getActivity/TitleBar
28-
implementation 'com.hjq:titlebar:6.5'
28+
implementation 'com.hjq:titlebar:8.0'
2929
// 悬浮窗:https://github.com/getActivity/XToast
3030
implementation 'com.hjq:xtoast:5.5'
3131
// 内存泄漏捕捉:https://github.com/square/leakcanary

app/src/main/java/com/hjq/toast/demo/ToastActivity.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import androidx.appcompat.app.AppCompatActivity;
88
import androidx.core.app.NotificationManagerCompat;
99

10-
import com.hjq.toast.SupportToast;
10+
import com.hjq.toast.CustomToast;
1111
import com.hjq.toast.ToastUtils;
1212
import com.hjq.toast.style.ToastAliPayStyle;
1313
import com.hjq.toast.style.ToastBlackStyle;
@@ -87,10 +87,10 @@ protected void onRestart() {
8787
// 请注意这段代码强烈建议不要放到实际开发中,因为用户屏蔽通知栏和开启应用状态下的概率极低,可以忽略不计
8888

8989
// 如果通知栏的权限被手动关闭了
90-
if (!SupportToast.class.equals(ToastUtils.getToast().getClass()) &&
90+
if (!CustomToast.class.equals(ToastUtils.getToast().getClass()) &&
9191
!NotificationManagerCompat.from(this).areNotificationsEnabled()) {
9292
// 因为吐司只有初始化的时候才会判断通知权限有没有开启,根据这个通知开关来显示原生的吐司还是兼容的吐司
93-
ToastUtils.setToast(new SupportToast(getApplication()));
93+
ToastUtils.setToast(new CustomToast(getApplication()));
9494
getWindow().getDecorView().postDelayed(new Runnable() {
9595
@Override
9696
public void run() {

library/build.gradle

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,20 @@ apply plugin: 'com.android.library'
22
apply plugin: 'com.novoda.bintray-release'
33

44
android {
5-
compileSdkVersion 26
5+
compileSdkVersion 30
66

77
defaultConfig {
8-
minSdkVersion 3
9-
targetSdkVersion 26
10-
versionCode 86
11-
versionName "8.6"
8+
minSdkVersion 4
9+
versionCode 88
10+
versionName "8.8"
1211
}
1312
}
1413

1514
publish {
1615
userOrg = 'getactivity'
1716
groupId = 'com.hjq'
1817
artifactId = 'toast'
19-
version = '8.6'
18+
version = '8.8'
2019
description = 'This is a very functional Toast'
2120
website = "https://github.com/getActivity/ToastUtils"
2221
}

library/src/main/java/com/hjq/toast/SupportToast.java renamed to library/src/main/java/com/hjq/toast/CustomToast.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
* author : Android 轮子哥
88
* github : https://github.com/getActivity/ToastUtils
99
* time : 2018/11/02
10-
* desc : Toast 无通知栏权限兼容
10+
* desc : 自定义 Toast(用于解决关闭通知栏权限之后不能弹吐司的问题和 Android 11 不能自定义吐司样式的问题)
1111
*/
12-
public final class SupportToast extends BaseToast {
12+
public final class CustomToast extends NormalToast {
1313

1414
/** 吐司弹窗显示辅助类 */
1515
private final ToastHelper mToastHelper;
@@ -27,20 +27,20 @@ public final class SupportToast extends BaseToast {
2727
/** 垂直间距百分比 */
2828
private float mVerticalMargin;
2929

30-
public SupportToast(Application application) {
30+
public CustomToast(Application application) {
3131
super(application);
3232
mToastHelper = new ToastHelper(this, application);
3333
}
3434

3535
@Override
3636
public void show() {
37-
// 显示吐司
37+
// 替换成 WindowManager 来显示
3838
mToastHelper.show();
3939
}
4040

4141
@Override
4242
public void cancel() {
43-
// 取消显示
43+
// 取消 WindowManager 的显示
4444
mToastHelper.cancel();
4545
}
4646

library/src/main/java/com/hjq/toast/IToastStrategy.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.hjq.toast;
22

3+
import android.app.Application;
34
import android.widget.Toast;
45

56
/**
@@ -16,7 +17,12 @@ public interface IToastStrategy {
1617
int LONG_DURATION_TIMEOUT = 3500;
1718

1819
/**
19-
* 绑定 Toast 对象
20+
* 创建 Toast
21+
*/
22+
Toast create(Application application);
23+
24+
/**
25+
* 绑定 Toast
2026
*/
2127
void bind(Toast toast);
2228

library/src/main/java/com/hjq/toast/BaseToast.java renamed to library/src/main/java/com/hjq/toast/NormalToast.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
* author : Android 轮子哥
1111
* github : https://github.com/getActivity/ToastUtils
1212
* time : 2018/11/03
13-
* desc : Toast 基类
13+
* desc : 普通的 Toast
1414
*/
15-
public class BaseToast extends Toast {
15+
public class NormalToast extends Toast {
1616

1717
/** 吐司消息 View */
1818
private TextView mMessageView;
1919

20-
public BaseToast(Application application) {
20+
public NormalToast(Application application) {
2121
super(application);
2222
}
2323

library/src/main/java/com/hjq/toast/SafeToast.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
* author : Android 轮子哥
1313
* github : https://github.com/getActivity/ToastUtils
1414
* time : 2018/12/06
15-
* desc : Toast 显示安全处理
15+
* desc : Toast 崩溃处理
1616
*/
1717
@TargetApi(Build.VERSION_CODES.KITKAT)
18-
public final class SafeToast extends BaseToast {
18+
public final class SafeToast extends NormalToast {
1919

2020
public SafeToast(Application application) {
2121
super(application);

library/src/main/java/com/hjq/toast/ToastStrategy.java

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
package com.hjq.toast;
22

3+
import android.app.AppOpsManager;
4+
import android.app.Application;
5+
import android.app.NotificationManager;
6+
import android.content.Context;
7+
import android.os.Build;
38
import android.os.Handler;
49
import android.os.Looper;
510
import android.os.Message;
611
import android.widget.Toast;
712

13+
import java.lang.reflect.Field;
14+
import java.lang.reflect.InvocationTargetException;
15+
import java.lang.reflect.Method;
816
import java.util.Queue;
917
import java.util.concurrent.ArrayBlockingQueue;
1018

@@ -43,6 +51,36 @@ public ToastStrategy() {
4351
mQueue = getToastQueue();
4452
}
4553

54+
@Override
55+
public Toast create(Application application) {
56+
Toast toast;
57+
// 初始化吐司
58+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
59+
// 适配 Android 11 无法使用自定义 Toast 的问题
60+
// 官方文档:https://developer.android.google.cn/preview/features/toasts
61+
toast = new CustomToast(application);
62+
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
63+
// 处理 Android 7.1 上 Toast 在主线程被阻塞后会导致报错的问题
64+
toast = new SafeToast(application);
65+
} else {
66+
boolean check =
67+
// 对比不同版本的 NMS 的源码发现这个问题在 Android 9.0 已经被谷歌修复了
68+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ||
69+
// 判断当前应用是否有通知栏权限,如果关闭会导致弹 Toast 无法显示
70+
areNotificationsEnabled(application) ||
71+
// 判断当前是否是小米手机,因为只有小米手机做了特殊处理,就算没有通知栏权限也能弹吐司
72+
"xiaomi".equals(Build.MANUFACTURER.toLowerCase());
73+
if (check) {
74+
// 检查通过,返回正常类型的 Toast 即可
75+
toast = new NormalToast(application);
76+
} else {
77+
// 修复关闭通知栏权限后 Toast 不显示的问题
78+
toast = new CustomToast(application);
79+
}
80+
}
81+
return toast;
82+
}
83+
4684
@Override
4785
public void bind(Toast toast) {
4886
mToast = toast;
@@ -122,7 +160,30 @@ public Queue<CharSequence> getToastQueue() {
122160
* 根据文本来获取吐司的显示时长
123161
*/
124162
public int getToastDuration (CharSequence text) {
125-
// 如果显示的文字超过了10个就显示长吐司,否则显示短吐司
163+
// 如果显示的文字超过了 20 个字符就显示长吐司,否则显示短吐司
126164
return text.length() > 20 ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
127165
}
166+
167+
/**
168+
* 检查通知栏权限有没有开启
169+
*
170+
* 参考 SupportCompat 包中的方法: NotificationManagerCompat.from(context).areNotificationsEnabled();
171+
*/
172+
private static boolean areNotificationsEnabled(Context context) {
173+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
174+
return context.getSystemService(NotificationManager.class).areNotificationsEnabled();
175+
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
176+
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
177+
try {
178+
Method method = appOps.getClass().getMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE, String.class);
179+
Field field = appOps.getClass().getDeclaredField("OP_POST_NOTIFICATION");
180+
int value = (Integer) field.get(Integer.class);
181+
return ((int) method.invoke(appOps, value, context.getApplicationInfo().uid, context.getPackageName())) == AppOpsManager.MODE_ALLOWED;
182+
} catch (NoSuchMethodException | NoSuchFieldException | InvocationTargetException | IllegalAccessException | RuntimeException ignored) {
183+
return true;
184+
}
185+
} else {
186+
return true;
187+
}
188+
}
128189
}

0 commit comments

Comments
 (0)