6.7.0 - Alpha21 - 增加 Toast.Callback 兜底超时逻辑以防止队列卡住
This commit is contained in:
@@ -34,6 +34,10 @@ object ScriptToast {
|
|||||||
private var currentToast: Toast? = null
|
private var currentToast: Toast? = null
|
||||||
private var currentFinishRunnable: Runnable? = null
|
private var currentFinishRunnable: Runnable? = null
|
||||||
|
|
||||||
|
// Fallback timeout runnable for API 30+ when Toast.Callback is not reliably invoked.
|
||||||
|
// zh-CN: 用于 API 30+ 场景的超时兜底 Runnable, 防止 Toast.Callback 不回调导致队列卡死.
|
||||||
|
private var currentFallbackTimeoutRunnable: Runnable? = null
|
||||||
|
|
||||||
private data class ToastTask(
|
private data class ToastTask(
|
||||||
val message: String,
|
val message: String,
|
||||||
val duration: Int,
|
val duration: Int,
|
||||||
@@ -73,6 +77,9 @@ object ScriptToast {
|
|||||||
currentFinishRunnable?.let { mainHandler.removeCallbacks(it) }
|
currentFinishRunnable?.let { mainHandler.removeCallbacks(it) }
|
||||||
currentFinishRunnable = null
|
currentFinishRunnable = null
|
||||||
|
|
||||||
|
currentFallbackTimeoutRunnable?.let { mainHandler.removeCallbacks(it) }
|
||||||
|
currentFallbackTimeoutRunnable = null
|
||||||
|
|
||||||
currentToast?.cancel()
|
currentToast?.cancel()
|
||||||
currentToast = null
|
currentToast = null
|
||||||
currentTask = null
|
currentTask = null
|
||||||
@@ -99,6 +106,9 @@ object ScriptToast {
|
|||||||
currentFinishRunnable?.let { mainHandler.removeCallbacks(it) }
|
currentFinishRunnable?.let { mainHandler.removeCallbacks(it) }
|
||||||
currentFinishRunnable = null
|
currentFinishRunnable = null
|
||||||
|
|
||||||
|
currentFallbackTimeoutRunnable?.let { mainHandler.removeCallbacks(it) }
|
||||||
|
currentFallbackTimeoutRunnable = null
|
||||||
|
|
||||||
currentToast?.cancel()
|
currentToast?.cancel()
|
||||||
currentToast = null
|
currentToast = null
|
||||||
currentTask = null
|
currentTask = null
|
||||||
@@ -118,7 +128,14 @@ object ScriptToast {
|
|||||||
currentToast = toast
|
currentToast = toast
|
||||||
|
|
||||||
val finish = Runnable {
|
val finish = Runnable {
|
||||||
|
// Ensure idempotency.
|
||||||
|
// zh-CN: 确保 finish 具备幂等性.
|
||||||
|
currentFinishRunnable?.let { mainHandler.removeCallbacks(it) }
|
||||||
currentFinishRunnable = null
|
currentFinishRunnable = null
|
||||||
|
|
||||||
|
currentFallbackTimeoutRunnable?.let { mainHandler.removeCallbacks(it) }
|
||||||
|
currentFallbackTimeoutRunnable = null
|
||||||
|
|
||||||
currentToast = null
|
currentToast = null
|
||||||
currentTask = null
|
currentTask = null
|
||||||
isShowing = false
|
isShowing = false
|
||||||
@@ -126,19 +143,42 @@ object ScriptToast {
|
|||||||
}
|
}
|
||||||
currentFinishRunnable = finish
|
currentFinishRunnable = finish
|
||||||
|
|
||||||
|
val delay = if (task.duration == Toast.LENGTH_LONG) 3_500L else 2_000L
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
// Fallback timeout:
|
||||||
|
// Some ROMs may not invoke Toast.Callback reliably, which would freeze the queue forever.
|
||||||
|
//
|
||||||
|
// zh-CN:
|
||||||
|
// 超时兜底:
|
||||||
|
// 某些 ROM 可能不会可靠触发 Toast.Callback, 否则队列会永久卡死.
|
||||||
|
val fallback = Runnable { finish.run() }
|
||||||
|
currentFallbackTimeoutRunnable = fallback
|
||||||
|
mainHandler.postDelayed(fallback, delay + 1_000L)
|
||||||
|
|
||||||
toast.addCallback(object : Toast.Callback() {
|
toast.addCallback(object : Toast.Callback() {
|
||||||
override fun onToastHidden() {
|
override fun onToastHidden() {
|
||||||
super.onToastHidden()
|
super.onToastHidden()
|
||||||
|
|
||||||
|
// Cancel fallback and finish immediately.
|
||||||
|
// zh-CN: 取消兜底计时并立即 finish.
|
||||||
|
currentFallbackTimeoutRunnable?.let { mainHandler.removeCallbacks(it) }
|
||||||
|
currentFallbackTimeoutRunnable = null
|
||||||
|
|
||||||
finish.run()
|
finish.run()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
val delay = if (task.duration == Toast.LENGTH_LONG) 3_500L else 2_000L
|
|
||||||
mainHandler.postDelayed(finish, delay)
|
mainHandler.postDelayed(finish, delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.show()
|
runCatching {
|
||||||
|
toast.show()
|
||||||
|
}.onFailure {
|
||||||
|
// If show() throws, release the queue immediately.
|
||||||
|
// zh-CN: 若 show() 抛异常, 立即释放队列避免卡死.
|
||||||
|
finish.run()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <E> ArrayDeque<E>.removeFirstOrNull(): E? =
|
private fun <E> ArrayDeque<E>.removeFirstOrNull(): E? =
|
||||||
|
|||||||
Reference in New Issue
Block a user