perf: use suspendCancellableCoroutine

This commit is contained in:
二刺螈
2026-03-18 14:09:37 +08:00
parent 8fa475fc1d
commit 16b0c235ef
5 changed files with 60 additions and 35 deletions

View File

@@ -14,6 +14,7 @@ import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runInterruptible
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import li.songe.gkd.META
@@ -42,7 +43,6 @@ import li.songe.selector.Selector
import java.util.concurrent.Executors
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
private val eventDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
@@ -200,15 +200,21 @@ class A11yRuleEngine(val service: A11yCommonImpl) {
}
// 某些场景耗时 5000 ms
private suspend fun getTimeoutActiveWindow(): AccessibilityNodeInfo? = suspendCoroutine { s ->
val temp = atomic<Continuation<AccessibilityNodeInfo?>?>(s)
scope.launch(Dispatchers.IO) {
delay(500L)
temp.getAndUpdate { null }?.resume(null)
}
scope.launch(Dispatchers.IO) {
val a = safeActiveWindow
temp.getAndUpdate { null }?.resume(a)
private suspend fun getTimeoutActiveWindow(): AccessibilityNodeInfo? {
return suspendCancellableCoroutine { s ->
val temp = atomic<Continuation<AccessibilityNodeInfo?>?>(s)
scope.launch(Dispatchers.IO) {
delay(500L)
if (s.isActive) {
temp.getAndUpdate { null }?.resume(null)
}
}
scope.launch(Dispatchers.IO) {
val a = safeActiveWindow
if (s.isActive) {
temp.getAndUpdate { null }?.resume(a)
}
}
}
}

View File

@@ -14,6 +14,7 @@ import android.view.accessibility.AccessibilityNodeInfo
import android.view.accessibility.AccessibilityWindowInfo
import com.google.android.accessibility.selecttospeak.SelectToSpeakService
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.suspendCancellableCoroutine
import li.songe.gkd.a11y.A11yCommonImpl
import li.songe.gkd.a11y.A11yRuleEngine
import li.songe.gkd.a11y.topActivityFlow
@@ -28,7 +29,6 @@ import li.songe.gkd.util.componentName
import li.songe.gkd.util.runMainPost
import li.songe.gkd.util.toast
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@SuppressLint("AccessibilityPolicy")
open class A11yService : AccessibilityService(), OnA11yLife, A11yCommonImpl {
@@ -36,26 +36,35 @@ open class A11yService : AccessibilityService(), OnA11yLife, A11yCommonImpl {
override val scope = useScope()
override val windowNodeInfo: AccessibilityNodeInfo? get() = rootInActiveWindow
override val windowInfos: List<AccessibilityWindowInfo> get() = windows
override suspend fun screenshot(): Bitmap? = suspendCoroutine { continuation ->
override suspend fun screenshot(): Bitmap? = suspendCancellableCoroutine { cont ->
if (AndroidTarget.R) {
takeScreenshot(
Display.DEFAULT_DISPLAY,
application.mainExecutor,
object : TakeScreenshotCallback {
override fun onFailure(errorCode: Int) = continuation.resume(null)
override fun onSuccess(screenshot: ScreenshotResult) = try {
continuation.resume(
Bitmap.wrapHardwareBuffer(
screenshot.hardwareBuffer, screenshot.colorSpace
)
)
} finally {
screenshot.hardwareBuffer.close()
override fun onFailure(errorCode: Int) {
if (cont.isActive) {
cont.resume(null)
}
}
override fun onSuccess(screenshot: ScreenshotResult) {
try {
if (cont.isActive) {
cont.resume(
Bitmap.wrapHardwareBuffer(
screenshot.hardwareBuffer, screenshot.colorSpace
)
)
}
} finally {
screenshot.hardwareBuffer.close()
}
}
}
)
} else {
continuation.resume(null)
cont.resume(null)
}
}

View File

@@ -10,10 +10,10 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.suspendCancellableCoroutine
import li.songe.gkd.util.stopCoroutine
import li.songe.gkd.util.throttle
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
data class AlertDialogOptions(
val title: @Composable (() -> Unit)? = null,
@@ -111,9 +111,11 @@ suspend fun MutableStateFlow<AlertDialogOptions?>.getResult(
dismissText: String = DEFAULT_DISMISS_TEXT,
error: Boolean = false,
): Boolean {
return suspendCoroutine { s ->
return suspendCancellableCoroutine { s ->
val dismiss = {
s.resume(false)
if (s.isActive) {
s.resume(false)
}
this.value = null
}
updateDialogOptions(
@@ -123,7 +125,9 @@ suspend fun MutableStateFlow<AlertDialogOptions?>.getResult(
onDismissRequest = if (dismissRequest) dismiss else ({}),
confirmText = confirmText,
confirmAction = {
s.resume(true)
if (s.isActive) {
s.resume(true)
}
this.value = null
},
dismissText = dismissText,

View File

@@ -14,29 +14,31 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.DialogProperties
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.suspendCancellableCoroutine
import li.songe.gkd.ui.WebViewRoute
import li.songe.gkd.ui.share.LocalMainViewModel
import li.songe.gkd.util.ShortUrlSet
import li.songe.gkd.util.subsItemsFlow
import li.songe.gkd.util.throttle
import li.songe.gkd.util.toast
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class InputSubsLinkOption {
private val showFlow = MutableStateFlow(false)
private val valueFlow = MutableStateFlow("")
private val initValueFlow = MutableStateFlow("")
private var continuation: Continuation<String?>? = null
private var continuation: CancellableContinuation<String?>? = null
private fun resume(value: String?) {
showFlow.value = false
valueFlow.value = ""
initValueFlow.value = ""
continuation?.resume(value)
if (continuation?.isActive == true) {
continuation?.resume(value)
}
continuation = null
}
@@ -65,7 +67,7 @@ class InputSubsLinkOption {
initValueFlow.value = initValue
valueFlow.value = initValue
showFlow.value = true
return suspendCoroutine {
return suspendCancellableCoroutine {
continuation = it
}
}

View File

@@ -15,9 +15,9 @@ import android.media.projection.MediaProjectionManager
import android.os.Handler
import android.os.Looper
import androidx.core.graphics.createBitmap
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
// https://github.com/npes87184/ScreenShareTile/blob/master/app/src/main/java/com/npes87184/screenshottile/ScreenshotService.kt
@@ -53,7 +53,7 @@ class ScreenshotUtil(
}
// TODO android13 上一半概率获取到全透明图片, android12 暂无此问题
suspend fun execute() = suspendCoroutine { block ->
suspend fun execute() = suspendCancellableCoroutine { cont ->
imageReader = ImageReader.newInstance(
width, height,
PixelFormat.RGBA_8888, 2
@@ -92,14 +92,18 @@ class ScreenshotUtil(
bitmap = Bitmap.createBitmap(bitmapWithStride, 0, 0, width, height)
if (!bitmap.isFullTransparent()) {
imageReader?.setOnImageAvailableListener(null, null)
block.resume(bitmap)
if (cont.isActive) {
cont.resume(bitmap)
}
resumed = true
}
}
} catch (e: Exception) {
e.printStackTrace()
imageReader?.setOnImageAvailableListener(null, null)
block.resumeWithException(e)
if (cont.isActive) {
cont.resumeWithException(e)
}
} finally {
bitmapWithStride?.recycle()
image?.close()