簡體   English   中英

在運行需要在主線程上運行的操作時避免 UI 阻塞

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM