我有可组合的
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
重组,直到知道应用程序主题为止?
您应该从活动之外的设置数据库中检索主题,并将其存储在全局变量中。然后在 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
在应用程序中的任何位置访问该变量