簡體   English   中英

如何在服務屬性更新時更新我的​​可組合?

[英]How to update my composable upon service property update?

我正在使用服務定位器(如https://developer.android.com/training/dependency-injection#di-alternatives中所建議的那樣,但稍后我會切換到適當的 DI,我保證)在我的應用程序中處理身份驗證。 我有一個身份驗證服務,它具有我使用logInlogOut方法設置和取消設置的user屬性

我希望我的ContentViewauth.user中的更改做出反應,但我不太清楚如何。 我已經嘗試by remember { mutableStateOf() }將其包裝,但我在登錄時沒有看到任何更新..知道我錯過了什么嗎?

在此先感謝(下面的片段)


@Composable
fn ContentView() {
    val auth = ServiceLocator.auth
    var loggedInUser: User? by remember { mutableStateOf(auth.user) }  // <-- I would like my composable to react to changes to auth.user

    if (loggedInUser) {
        ViewA()
    } else {
        ViewB()
    }
}

object ServiceLocator {
    val auth = AuthenticationService()
}

class AuthenticationService {

    var user: User? = null

    fun logIn() { 
        // sets user...
    }

    fun logOut() {
        // undefs user...
    }

在此行的代碼段中

var loggedInUser: User? by remember { mutableStateOf(auth.user) }

您正在創建一個MutableState<User?>的實例,其初始值是當時由auth.user引用的值。 由於remember { } ,這種初始化僅在可組合的ContentView進入組合時發生,然后MutableState實例在重新組合中被記住並重用。

如果您稍后更改變量auth.user不會發生重組,因為存儲在loggedInUser (處於可變狀態)中的值沒有更改。

mutableStateOf的文檔解釋了這個調用在幕后的實際作用

返回使用傳入值初始化的新MutableState

MutableState class 是一個單值持有者,其讀寫被 Compose 觀察。 此外,對它的寫入作為Snapshot系統的一部分進行處理。

讓我們剖析一下這條信息。

返回使用傳入值初始化的新 MutableState。

調用mutableStateOf返回一個MutableState實例,該實例使用作為參數傳遞的值進行初始化。

MutableState class 是單值持有者

此 class 的每個實例都存儲一個值 state。 它可能會出於實現目的存儲其他值,但它僅公開 state 的單個值。

Compose 觀察到其讀取和寫入

Compose 觀察發生在MutableState實例上的讀取和寫入

這是您錯過的信息。 寫入需要發生在 MutableState 的實例(在您的情況下為loggedInUser ),而不是發生在已作為初始值傳入的變量(在您的情況下為auth.user )。

如果你仔細想想,Kotlin 中沒有內置機制來觀察變量的變化,所以 Compose 必須有一個包裝器才能觀察到變化是可以理解的。 而且我們必須通過包裝器更改 state 而不是直接更改變量。


知道所有你可以將可變的 state 移動到AuthenticationService中,一切都會奏效

import androidx.compose.runtime.mutableStateOf

class AuthenticationService {
    var user: User? by mutableStateOf(null)
        private set
    
    // ... rest of the service
}

@Composable
fun ContentView() {
    val auth = ServiceLocator.auth
    // no remember { } block this time because now the MutableState reference is being kept by
    // the AuthenticationService so it won't reset on recomposition
    val loggedInUser = auth.user

    if (loggedInUser != null) {
        ViewA()
    } else {
        ViewB()
    }
}

但是,現在您的AuthenticationService依賴於mutableStateOf ,因此依賴於您可能想要避免的 Composable 運行時。 “服務”(或存儲庫)不需要了解有關 UI 實現的詳細信息。

還有其他選項可以跟蹤 state 更改並且不依賴於 Compose 運行時。 來自文檔部分Compose 和其他庫

Compose 附帶了適用於 Android 最流行的基於流的解決方案的擴展。 這些擴展中的每一個都由不同的工件提供:

  • Flow.collectAsState()不需要額外的依賴項。 (因為它是kotlinx-coroutines-core的一部分)

  • LiveData.observeAsState()包含在androidx.compose.runtime:runtime-livedata:$composeVersion工件中。

  • Observable.subscribeAsState()包含在androidx.compose.runtime:runtime-rxjava2:$composeVersionandroidx.compose.runtime:runtime-rxjava3:$composeVersion工件中。

這些工件注冊為偵聽器,並將值表示為State 每當發出新值時,Compose 都會重新組合 UI 中使用該state.value的那些部分。

使用 Kotlin MutableStateFlow的示例

// No androidx.compose.* dependencies anymore
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow

class AuthenticationService {
    private val user = MutableStateFlow<User?>(null)
    val userFlow = user.asStateFlow()

    fun logIn() {
        user.value = User(/* potential parameters */)
    }

    fun logOut() {
        user.value = null
    }
}

然后在可組合中,我們將流收集為 state。

import androidx.compose.runtime.collectAsState

@Composable
fun ContentView() {
    val auth = ServiceLocator.auth
    val loggedInUser = auth.userFlow.collectAsState().value

    if (loggedInUser != null) {
        ViewA()
    } else {
        ViewB()
    }
}

要了解有關在 Compose 中使用 state 的更多信息,請參閱有關管理 State的文檔部分。 這是能夠在 Compose 中使用 state 並有效觸發重組的基本信息。 它還涵蓋了state 吊裝的基礎知識。 如果您更喜歡親身體驗 ,請參閱 Jetpack Compose 中 State 的代碼實驗室

最終(當您的應用程序變得復雜時)您可能希望在您的服務/存儲庫層和您的 UI 層(可組合)之間放置另一層。 將保存和管理 UI state 的層,因此您將能夠涵蓋正面結果(成功登錄)和負面結果(登錄失敗)。

如果您采用 MVVM (Model-View-ViewModel) 方式或 MVI (Model-View-Intent) 方式,則該層將被ViewModel覆蓋。 在這種情況下,可組合項僅管理一些瞬態 UI state 自己,同時他們獲得(或觀察)UI state 的 rest 並從 VM 調用 VM 以執行操作。 然后,VM 與服務/存儲庫層交互並相應地更新 UI state。 隨着復雜性的增加,有關處理 state 的介紹在來自 Google 的視頻中關於使用 Jetpack Compose 的自動 state 觀察

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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