如何在 Compose 中首次重新组合之前更改应用程序主题?

问题描述 投票:0回答:1

我有可组合的

MainScreen
SettingsScreen
。它们都共享一个共同的 ViewModel
SettingsViewModel
,负责读取和保存主题设置。

MainActivity
中,在创建
MainScreen
之前,我得到
SettingsViewModel
,它在内部接收有关应用程序使用哪个主题的数据(通过 DataStore)。然后我将主题作为应用程序的主题参数传递。

但问题是,默认值(来自 ViewModel)首先加载,延迟后加载来自 DataStore 的实际值。我缺少什么?为什么会有这么大的延迟(几乎一秒)以及如何避免它?

我的

MainActivity

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val viewModel: SettingsViewModel = hiltViewModel()
            val colorScheme = viewModel.colorScheme.collectAsState()// TODO loaded with default value first :(
            Log.d("TAG", "MainActivity theme $colorScheme")
            MyAppTheme(
                darkTheme = when(colorScheme.value){
                    ColorScheme.AUTO -> isSystemInDarkTheme()
                    ColorScheme.LIGHT -> false
                    ColorScheme.DARK -> true
                }
            ) {
                // MainScreen
            }
        }
    }
}

我的

SettingsViewModel

enum class ColorScheme{
    AUTO, LIGHT, DARK
}

@HiltViewModel
class SettingsViewModel @Inject constructor(
    private val settingsRepository: SettingsRepository
): ViewModel() {
    private val _colorScheme = MutableStateFlow(ColorScheme.AUTO)
    val colorScheme: StateFlow<ColorScheme>
        get() = _colorScheme

    init {
        Log.d("TAG", "SettingsViewModel init")
        // Load settings
        viewModelScope.launch {
            _colorScheme.emit(ColorScheme.values()[settingsRepository.loadColorScheme()])
            Log.d("TAG", "SettingsViewModel load & emit")
        }
    }

    fun setColorScheme(colorScheme: ColorScheme){
        _colorScheme.tryEmit(colorScheme)
        viewModelScope.launch {
            settingsRepository.saveColorScheme(colorScheme)
        }
    }
}

我的Logcat

2023-08-13 11:34:22.315 SettingsViewModel init
2023-08-13 11:34:22.326 MainActivity theme = MutableState(value=AUTO)
2023-08-13 11:34:23.105 SettingsViewModel load & emit
2023-08-13 11:34:23.124 MainActivity theme = MutableState(value=LIGHT)

我已经尝试从

SettingsViewModel
中删除默认值,但在第一次
MainScreen
重组时,主题变量尚未初始化。也许您可以以某种方式推迟
MainScreen
重组,直到知道应用程序主题为止?

android android-jetpack-compose android-theme darkmode android-dark-theme
1个回答
0
投票

您应该从活动之外的设置数据库中检索主题,并将其存储在全局变量中。然后在 ViewModel 的

init
块中加载该全局变量,而不是加载当前使用的任何默认值。

最简单的方法是创建一个持久性应用程序类,当应用程序唤醒时,在初始化任何活动之前,您在应用程序的

onCreate()
中运行的任何内容都将立即运行。

在您的清单中:

<application
        android:name=".App"
        android:persistent="true"
        ...
</application>

以及您的应用程序类:

class App: Application() {

    lateinit var colorScheme: ColorScheme

    override fun onCreate() {
        super.onCreate()

        // read the theme variable here (probably inside an IO CoroutineScope)
        colorScheme = ...
    }
}

您可以通过调用

App.colorScheme

在应用程序中的任何位置访问该变量
© www.soinside.com 2019 - 2024. All rights reserved.