[英]Avoid UI Blocking while running an operation that requires to be run on the main thread
我使用一個 API 有一個方法,假設run()
必須在主線程上執行,否則它會拋出異常。 現在,我已經嘗試過協程,它在標准的launch{...}
塊中不起作用,這是可以理解的。 現在,由於這是一個運行時間較長的任務,我希望向用戶顯示一個 UI,表明相同的情況,即一個進程正在發生。 現在,我不需要有關 animation 邏輯的幫助,但我不明白 animation 應該如何跟上主線程上可能正在進行的所有繁重的 IO 工作。
此外,我在這個可組合項中遇到了一些非常奇怪的行為。 君臨天下看看,
@Composable
fun CustomC() {
var trigger by remember {
mutableStateOf(false)
}
val color by animateColorAsState(targetValue = if (trigger) Color.Gray else Color.Cyan)
Surface(Modifier.fillMaxSize()) {
Text(
modifier = Modifier.background(color),
text = "Running"
)
}
// I tried this but this seems to produce a crash, indicating that the run method is not running on the main thread, but how? Removing this LaunchedEffect removes the error.
// LaunchedEffect(Unit){
// delay(2000)
// trigger = true
// }
run() // Must be executed on the Main Thread
}
如果我把那個LaunchedEffect
塊放在那里,這個應用程序就會崩潰,但據我所知,它甚至沒有以任何方式與run()
交互。 另一個奇怪的行為如下:
@Composable
fun CustomC() {
var trigger by remember {
mutableStateOf(false)
}
val color by animateColorAsState(targetValue = if (trigger) Color.Gray else Color.Cyan)
Surface(Modifier.fillMaxSize()) {
Text(
modifier = Modifier.background(color),
text = "Running"
)
}
trigger = true
run() // Must be executed on the Main Thread
}
現在,您會期望 Composable 在調用 run 方法之前變成青色,對嗎? 它沒有! 它只是不TTTT
它只是開始執行run()
,然后最終在方法執行完畢之后,可組合項變為青色。 這清楚地意味着在方法運行時重組被阻止,所以我需要的只是一種解決這個問題的方法。
編輯:我之前錯過的一條重要信息,當我在LaunchedEffect
中調用run()
方法時,該方法似乎工作正常,即應用程序沒有崩潰,但 UI 仍然被阻止。
此外,如果我在LaunchedEffect
內的launch
塊內調用該方法,則會發生與上面相同的事情,該方法運行正常但 UI 被阻塞。 那么launch
在這里的作用是什么?
最終編輯:我在這種情況下看到的一件非常罕見的事情是當崩潰出現時,它沒有拋出任何類型的異常。 它只是引發了這樣的錯誤:
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x2f6000412f6018 in tid 29693
我從我的搜索歷史中得到這個錯誤,它向我指出了一些與 NDK 中的編程相關的事情,而我沒有。 另外,現在無論我做什么,都不會出現錯誤。 似乎是 Android 或 Studio 中的一個小故障。
由於崩潰的原因似乎是該方法未被系統授予對 I/O 的訪問權限,因此使用具有 I/O 訪問權限的協程解決了該問題。
現在,在我的ViewModel
中,我將 run 方法包裝在這樣的協程中
suspend fun runWithIO(){ // custom method
withContext(Dispatchers.IO){
run() // The original method, provided by the API
}
}
這滿足了所有約束,無論如何 - 在具有 I/O 訪問權限的線程上運行,不阻塞主線程,使用協程等最佳實踐,沒有任何副作用。
因此,Johann 在原始帖子的第一條評論中發布了解釋,該帖子剛剛根據我的特定用例進行了調整。
因此,如果您可能正在使用的 API 聲明這些方法應該僅在主線程上運行,您可能應該嘗試使用不同的協程上下文,因為 API 可能只需要主線程執行 I /O 操作,也可以在像這樣的簡單協程中執行。 如果該方法確實需要主線程,還有Dispatchers.Main
可以幫助您,您可以在主線程上只運行 function 的所需部分,但請注意,此調用將被阻塞。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.