77import android .app .NotificationManager ;
88import android .content .Context ;
99import android .os .Build ;
10- import android .os .Build .VERSION ;
11- import android .os .Build .VERSION_CODES ;
1210import android .os .Handler ;
1311import android .os .Looper ;
1412import android .os .SystemClock ;
@@ -95,19 +93,19 @@ public int computeShowDuration(CharSequence text) {
9593
9694 @ Override
9795 public IToast createToast (ToastParams params ) {
98- Activity foregroundActivity = getForegroundActivity ();
96+ Activity availableActivity = getAvailableActivity ();
9997 IToast toast ;
10098 if ((params .priorityType == ToastParams .PRIORITY_TYPE_DEFAULT ||
10199 params .priorityType == ToastParams .PRIORITY_TYPE_GLOBAL ) &&
102100 Build .VERSION .SDK_INT >= Build .VERSION_CODES .M &&
103101 Settings .canDrawOverlays (mApplication )) {
104102 // 如果有悬浮窗权限,就开启全局的 Toast
105103 toast = new GlobalToast (mApplication );
106- } else if (( params . priorityType == ToastParams . PRIORITY_TYPE_DEFAULT ||
107- params .priorityType == ToastParams .PRIORITY_TYPE_LOCAL ) &&
108- isActivityAvailable ( foregroundActivity )) {
104+ } else if (availableActivity != null &&
105+ ( params .priorityType == ToastParams .PRIORITY_TYPE_DEFAULT ||
106+ params . priorityType == ToastParams . PRIORITY_TYPE_LOCAL )) {
109107 // 如果没有悬浮窗权限,就开启一个依附于 Activity 的 Toast
110- toast = new ActivityToast (foregroundActivity );
108+ toast = new ActivityToast (availableActivity );
111109 } else if (Build .VERSION .SDK_INT == Build .VERSION_CODES .N_MR1 ) {
112110 // 处理 Android 7.1 上 Toast 在主线程被阻塞后会导致报错的问题
113111 toast = new SafeToast (mApplication );
@@ -175,14 +173,7 @@ protected static Handler getHandler() {
175173 * 生成默认延迟时间
176174 */
177175 protected int generateShowDelayTime (ToastParams params ) {
178- // 延迟一段时间之后再执行,因为在没有通知栏权限的情况下,Toast 只能显示在当前 Activity 上面(即使用 ActivityToast)
179- // 如果当前 Activity 在 showToast 之后立马进行 finish 了,那么这个时候 Toast 可能会显示不出来
180- // 因为 Toast 会显示在销毁 Activity 界面上,而不会显示在新跳转的 Activity 上面,所以会导致显示不出来的问题
181- // 另外有悬浮窗权限的情况下,使用全局的 Toast(即使用 GlobalToast),这种立刻显示也会有一些问题
182- // 我在小米 12 Android 12 的手机上面测试,从权限设置页返回的时候,发现 Toast 有几率会从左上的位置显示,然后会变回正常的位置
183- // 如果是系统的 Toast(即使用 SystemToast、SafeToast、NotificationToast 任意一个)则不会有这个问题
184- // 300 只是一个经验值,经过很多次验证得出来的值,当然你觉得这个值不是自己想要的,也可以重写此方法改成自己想要的
185- return 300 ;
176+ return 100 ;
186177 }
187178
188179 /**
@@ -327,27 +318,40 @@ protected boolean areNotificationsEnabled(Context context) {
327318 }
328319
329320 /**
330- * 获取前台的 Activity
321+ * 获取可用的 Activity
331322 */
332- protected Activity getForegroundActivity () {
333- return ActivityStack .getInstance ().getForegroundActivity ();
334- }
323+ protected Activity getAvailableActivity () {
324+ Activity visibleActivity = ActivityStack .getInstance ().getVisibleActivity ();
325+ Activity focusActivity = ActivityStack .getInstance ().getFocusActivity ();
326+ if (focusActivity == null || visibleActivity == null ) {
327+ return null ;
328+ }
335329
336- /**
337- * Activity 是否可用
338- */
339- protected boolean isActivityAvailable (Activity activity ) {
340- if (activity == null ) {
341- return false ;
330+ if (focusActivity != visibleActivity ) {
331+ return null ;
342332 }
343333
344- if (activity .isFinishing ()) {
345- return false ;
334+ if (visibleActivity .isFinishing ()) {
335+ return null ;
346336 }
347337
348- if (VERSION .SDK_INT >= VERSION_CODES .JELLY_BEAN_MR1 ) {
349- return ! activity . isDestroyed () ;
338+ if (Build . VERSION .SDK_INT >= Build . VERSION_CODES .JELLY_BEAN_MR1 && visibleActivity . isDestroyed () ) {
339+ return null ;
350340 }
351- return true ;
341+
342+ long resumedActivityTime = ActivityStack .getInstance ().getActivityResumedTime ();
343+ // 如果这个 Activity 可见时长没有超过 200 毫秒,则证明 Activity 是刚跳转的,
344+ // 在这种情况下,如果直接拿来显示 WindowManager 是会有问题的,在 Android 16 上面会出现残影的情况
345+ // Github issue 地址:https://github.com/getActivity/Toaster/issues/150
346+ // 目前能想到比较好的解决方案是:必须 Activity 可见时长超过 200 毫秒才可以,
347+ // 否则就不能用 Activity 来显示 Toast,只能用系统的 Toast 来显示了,
348+ // 如果你想要在 startActivity 的时候,又能显示自定义 Toast 的效果,
349+ // 建议在显示 show 的时候加一下延迟显示,建议设置在 500 毫秒及以上,
350+ // 以确保 Toast 在显示的时候不受 Android 16 残影问题的影响。
351+ if (System .currentTimeMillis () - resumedActivityTime < 200 ) {
352+ return null ;
353+ }
354+
355+ return visibleActivity ;
352356 }
353357}
0 commit comments