Skip to content

Commit

Permalink
修复SupportToast在Activity跳转时没有显示的问题,优化线程安全的问题,优化一些代码
Browse files Browse the repository at this point in the history
  • Loading branch information
880634 committed Apr 18, 2019
1 parent a25109a commit 7090639
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 61 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#### 集成步骤

dependencies {
implementation 'com.hjq:toast:5.8'
implementation 'com.hjq:toast:6.0'
}

#### 初始化Toast
Expand Down
Binary file modified ToastUtils.apk
Binary file not shown.
6 changes: 3 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ android {
applicationId "com.hjq.toast.demo"
minSdkVersion 14
targetSdkVersion 26
versionCode 58
versionName "5.8"
versionCode 60
versionName "6.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
Expand All @@ -26,5 +26,5 @@ dependencies {
// 标题栏:https://github.com/getActivity/TitleBar
implementation 'com.hjq:titlebar:5.0'
// 悬浮窗:https://github.com/getActivity/XToast
implementation 'com.hjq:xtoast:2.0'
implementation 'com.hjq:xtoast:2.6'
}
6 changes: 4 additions & 2 deletions app/src/main/java/com/hjq/toast/demo/ToastActivity.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package com.hjq.toast.demo;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.View;
import android.widget.Toast;

import com.hjq.toast.ToastUtils;
import com.hjq.toast.style.ToastAlipayStyle;
import com.hjq.toast.style.ToastAliPayStyle;
import com.hjq.toast.style.ToastBlackStyle;
import com.hjq.toast.style.ToastQQStyle;
import com.hjq.toast.style.ToastWhiteStyle;
Expand Down Expand Up @@ -60,7 +62,7 @@ public void show5(View v) {
}

public void show6(View v) {
ToastUtils.initStyle(new ToastAlipayStyle());
ToastUtils.initStyle(new ToastAliPayStyle());
ToastUtils.show("支付宝那种还不简单,分分钟的事");
}

Expand Down
6 changes: 3 additions & 3 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ android {
defaultConfig {
minSdkVersion 3
targetSdkVersion 26
versionCode 58
versionName "5.8"
versionCode 60
versionName "6.0"
}
}

publish {
userOrg = 'getactivity'//填写bintray用户名,注意大小写
groupId = 'com.hjq'//定义的maven group id最终引用形式
artifactId = 'toast'//maven的artifact id
version = '5.8'//maven 上发布版本号
version = '6.0'//maven 上发布版本号
description = 'This is a very functional Toast'//描述,自己定义
website = "https://github.com/getActivity/ToastUtils"//项目在github中的地址
}
Expand Down
14 changes: 8 additions & 6 deletions library/src/main/java/com/hjq/toast/BaseToast.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* time : 2018/11/03
* desc : Toast 基类
*/
class BaseToast extends Toast {
public class BaseToast extends Toast {

// 吐司消息 View
private TextView mMessageView;
Expand All @@ -36,15 +36,17 @@ public void setText(CharSequence s) {
* 智能获取用于显示消息的 TextView
*/
private static TextView getMessageView(View view) {
TextView messageView;
if (view instanceof TextView) {
messageView = (TextView) view; return messageView;
return (TextView) view;
} else if (view.findViewById(android.R.id.message) instanceof TextView) {
messageView = ((TextView) view.findViewById(android.R.id.message)); return messageView;
return ((TextView) view.findViewById(android.R.id.message));
} else if (view instanceof ViewGroup) {
if ((messageView = findTextView((ViewGroup) view)) != null) return messageView;
TextView textView = findTextView((ViewGroup) view);
if (textView != null) {
return textView;
}
}
// 如果设置的布局没有包含一个 TextView 则抛出异常,必须要包含一个 TextView 作为 Message View
// 如果设置的布局没有包含一个 TextView 则抛出异常,必须要包含一个 TextView 作为 MessageView
throw new IllegalArgumentException("The layout must contain a TextView");
}

Expand Down
16 changes: 11 additions & 5 deletions library/src/main/java/com/hjq/toast/ToastHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ final class ToastHandler extends Handler {
static final int SHORT_DURATION_TIMEOUT = 2000; // 短吐司显示的时长
static final int LONG_DURATION_TIMEOUT = 3500; // 长吐司显示的时长

private static final int DELAY_TIMEOUT = 300; // 延迟时间

private static final int TYPE_SHOW = 1; // 显示吐司
private static final int TYPE_CONTINUE = 2; // 继续显示
private static final int TYPE_CANCEL = 3; // 取消显示
Expand Down Expand Up @@ -55,7 +57,10 @@ void add(CharSequence s) {
void show() {
if (!isShow) {
isShow = true;
sendEmptyMessage(TYPE_SHOW);
// 延迟一段时间之后再执行,因为在没有通知栏权限的情况下,Toast 只能显示当前 Activity
// 如果当前 Activity 在 ToastUtils.show 之后进行 finish 了,那么这个时候 Toast 可能会显示不出来
// 因为 Toast 会显示在销毁 Activity 界面上,而不会显示在新跳转的 Activity 上面
sendEmptyMessageDelayed(TYPE_SHOW, DELAY_TIMEOUT);
}
}

Expand All @@ -75,9 +80,10 @@ public void handleMessage(Message msg) {
if (text != null) {
mToast.setText(text);
mToast.show();
// 等这个 Toast 显示完后再继续显示,要加上一些延迟,不然在某些手机上 Toast 可能会来不及消失
sendEmptyMessageDelayed(TYPE_CONTINUE, getToastDuration(text) + 300);
}else {
// 等这个 Toast 显示完后再继续显示,要加上一些延迟
// 不然在某些手机上 Toast 可能会来不及消失就要进行显示,这样是显示不出来的
sendEmptyMessageDelayed(TYPE_CONTINUE, getToastDuration(text) + DELAY_TIMEOUT);
} else {
isShow = false;
}
break;
Expand All @@ -86,7 +92,7 @@ public void handleMessage(Message msg) {
mQueue.poll();
if (!mQueue.isEmpty()) {
sendEmptyMessage(TYPE_SHOW);
}else {
} else {
isShow = false;
}
break;
Expand Down
24 changes: 14 additions & 10 deletions library/src/main/java/com/hjq/toast/ToastHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ final class ToastHelper extends Handler {
super(Looper.getMainLooper());
mToast = toast;
mPackageName = application.getPackageName();
mWindowHelper = new WindowHelper(this, application);
mWindowHelper = WindowHelper.register(this, application);
}

@Override
public void handleMessage(Message msg) {
// super.handleMessage(msg);
// 收到取消显示的消息
cancel();
}

Expand All @@ -52,24 +52,25 @@ void show() {
这里解释一下,为什么不复用 WindowManager.LayoutParams 这个对象
因为如果复用了,不同 Activity 之间不能共用一个,第一个 Activity 调用显示方法可以显示出来,但是会导致后面的 Activity 都显示不出来
又或者说,非第一次调用显示方法的 Activity 都会把这个显示请求推送给之前第一个调用显示的 Activity 上面,如果第一个 Activity 已经销毁,还会报以下异常
android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@ef1ccb6 is not valid; is your activity running?
android.view.WindowManager$BadTokenException:
Unable to add window -- token android.os.BinderProxy@ef1ccb6 is not valid; is your activity running?
*/
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();

/*
// 为什么不能加 TYPE_TOAST,因为通知权限在关闭后设置显示的类型为Toast会报错
// 为什么不能加 TYPE_TOAST,因为通知权限在关闭后设置显示的类型为 Toast 会报错
// android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
params.type = WindowManager.LayoutParams.TYPE_TOAST;
*/

/*
// 这个是旧版本的写法,新版本已经废弃,因为 Activity onPause 方法被调用后这里把 Toast 取消显示了
// 这个是旧版本的写法,新版本已经废弃,因为 Activity onPause 方法被调用后这里把 Toast 取消显示了,这样做的原因:防止内存泄露
// 判断是否为 Android 6.0 及以上系统并且有悬浮窗权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(mToast.getView().getContext())) {
// 解决使用 WindowManager 创建的 Toast 只能显示在当前 Activity 的问题
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}else {
} else {
params.type = WindowManager.LayoutParams.TYPE_PHONE;
}
}
Expand All @@ -90,12 +91,14 @@ void show() {

try {
// 如果这个 View 对象被重复添加到 WindowManager 则会抛出异常
// java.lang.IllegalStateException: View android.widget.TextView{3d2cee7 V.ED..... ......ID 0,0-312,153} has already been added to the window manager.
// java.lang.IllegalStateException:
// View android.widget.TextView has already been added to the window manager.
mWindowHelper.getWindowManager().addView(mToast.getView(), params);
// 当前已经显示
isShow = true;
// 添加一个移除吐司的任务
sendEmptyMessageDelayed(0, mToast.getDuration() == Toast.LENGTH_LONG ? ToastHandler.LONG_DURATION_TIMEOUT : ToastHandler.SHORT_DURATION_TIMEOUT);
sendEmptyMessageDelayed(0, mToast.getDuration() == Toast.LENGTH_LONG ?
ToastHandler.LONG_DURATION_TIMEOUT : ToastHandler.SHORT_DURATION_TIMEOUT);
} catch (NullPointerException | IllegalStateException | WindowManager.BadTokenException ignored) {}
}
}
Expand All @@ -109,9 +112,10 @@ void cancel() {
if (isShow) {
try {
// 如果当前 WindowManager 没有附加这个 View 则会抛出异常
// java.lang.IllegalArgumentException: View=android.widget.TextView{3d2cee7 V.ED..... ........ 0,0-312,153} not attached to window manager
// java.lang.IllegalArgumentException:
// View=android.widget.TextView not attached to window manager
mWindowHelper.getWindowManager().removeView(mToast.getView());
}catch (NullPointerException | IllegalArgumentException ignored) {}
} catch (NullPointerException | IllegalArgumentException ignored) {}
// 当前没有显示
isShow = false;
}
Expand Down
65 changes: 40 additions & 25 deletions library/src/main/java/com/hjq/toast/ToastUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public final class ToastUtils {
private static Toast sToast;

/**
* 私有化构造函数
* 不允许外部实例化
*/
private ToastUtils() {}

Expand All @@ -51,31 +51,30 @@ public static void init(Application application, IToastStyle style) {
}

/**
* 初始化ToastUtils,在Application中初始化
* 初始化 ToastUtils,在Application中初始化
*
* @param application 应用的上下文
*/
public static void init(Application application) {
// 检查默认样式是否为空,如果是就创建一个默认样式
// 初始化样式
if (sDefaultStyle == null) {
sDefaultStyle = new ToastBlackStyle();
// 如果样式没有指定就初始化一个默认的样式
initStyle(new ToastBlackStyle());
}

// 判断有没有通知栏权限
// 初始化吐司
if (isNotificationEnabled(application)) {
// 解决 Android 7.1 上发现主线程被阻塞后吐司会报错的问题
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
sToast = new SafeToast(application);
}else {
sToast = new BaseToast(application);
// 解决 Android 7.1 上主线程被阻塞后吐司会报错的问题
setToast(new SafeToast(application));
} else {
setToast(new BaseToast(application));
}
}else {
sToast = new SupportToast(application);
} else {
// 解决关闭通知栏权限后 Toast 不显示的问题
setToast(new SupportToast(application));
}

// 创建一个吐司处理类
sToastHandler = new ToastHandler(sToast);

// 初始化布局
setView(createTextView(application.getApplicationContext()));

Expand All @@ -99,14 +98,13 @@ public static void show(Object object) {
* 如果不是则显示一个整数的string
*/
public static void show(int id) {

checkToastState();

try {
// 如果这是一个资源id
// 如果这是一个资源 id
show(sToast.getView().getContext().getResources().getText(id));
} catch (Resources.NotFoundException ignored) {
// 如果这是一个int类型
// 如果这是一个 int 数据
show(String.valueOf(id));
}
}
Expand All @@ -116,8 +114,7 @@ public static void show(int id) {
*
* @param text 需要显示的文本
*/
public static void show(CharSequence text) {

public static synchronized void show(CharSequence text) {
checkToastState();

if (text == null || "".equals(text.toString())) return;
Expand All @@ -129,8 +126,9 @@ public static void show(CharSequence text) {
/**
* 取消吐司的显示
*/
public static void cancel() {
public static synchronized void cancel() {
checkToastState();

sToastHandler.cancel();
}

Expand Down Expand Up @@ -161,7 +159,6 @@ public static void setView(int layoutId) {
setView(View.inflate(sToast.getView().getContext().getApplicationContext(), layoutId, null));
}
public static void setView(View view) {

checkToastState();

// 这个 View 不能为空
Expand All @@ -182,6 +179,15 @@ public static void setView(View view) {
}
}

/**
* 获取当前 Toast 的视图
*/
public static <V extends View> V getView() {
checkToastState();

return (V) sToast.getView();
}

/**
* 统一全局的Toast样式,建议在{@link android.app.Application#onCreate()}中初始化
*
Expand All @@ -201,6 +207,14 @@ public static void initStyle(IToastStyle style) {
}
}

/**
* 设置当前Toast对象
*/
public static void setToast(Toast toast) {
// 创建一个吐司处理类
sToastHandler = new ToastHandler(sToast = toast);
}

/**
* 获取当前Toast对象
*/
Expand Down Expand Up @@ -240,20 +254,21 @@ private static TextView createTextView(Context context) {
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sDefaultStyle.getPaddingBottom(), context.getResources().getDisplayMetrics()));

textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));

// setBackground API 版本兼容
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
textView.setBackground(drawable);
}else {
} else {
textView.setBackgroundDrawable(drawable);
}

// 设置 Z 轴阴影
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// 设置 Z 轴阴影
textView.setZ(sDefaultStyle.getZ());
}

// 设置最大显示行数
if (sDefaultStyle.getMaxLines() > 0) {
// 设置最大显示行数
textView.setMaxLines(sDefaultStyle.getMaxLines());
}

Expand All @@ -262,7 +277,7 @@ private static TextView createTextView(Context context) {

/**
* 检查通知栏权限有没有开启
* 参考SupportCompat包中的方法: NotificationManagerCompat.from(context).areNotificationsEnabled();
* 参考 SupportCompat 包中的方法: NotificationManagerCompat.from(context).areNotificationsEnabled();
*/
private static boolean isNotificationEnabled(Context context){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Expand Down
Loading

0 comments on commit 7090639

Please sign in to comment.