我有一个关于android ViewModels的架构问题:
假设我的应用程序中有一个包含两个片段的Activity(使用Viewpager).这两个片段做了不同的事情(因此可能有自己的ViewModel?),但它们也需要各种类似的数据.
例如,如果网络连接可用或不存在(并且两个片段在没有连接的情况下显示不同的错误UI),或者某些用户设置来自服务器并且同等地影响两个片段,则这是状态.
这看起来像这样:
现在我的问题是如何在使用ViewModels时处理这种情况?视图是否观察多个ViewModel是好的,就像我有一个ViewModel用于Activity(保持两个都需要的状态)和每个片段一个,如下所示:
这在这里暗示,但这不是一个好的做法,因为MVVM中的关系通常是
查看n - 1 ViewModel n - 1模型
但我不确定这种共享LiveData的正确位置在哪里?
我正在使用导航组件,我希望在几个片段之间共享一个视图模型,但是当我离开片段时应该清除它们(因此没有将它们范围限定到活动中)我试图将一个活动放在多个片段中方法。我已经设法使用多个导航主机实现了这一点,并使用 getParentFragment 将片段范围限定到它,但这只会导致更多的问题不得不将片段包装在其他父片段中,失去后退按钮无缝工作和其他黑客来获得一些应该工作的东西很简单。有没有人有关于如何实现这一目标的好主意?我想知道我是否可以使用 getViewModelStore 的任何东西,鉴于下面的图像,我想将视图模型范围限定为 createCardFragment2 并在它之后的任何内容中使用它(addPredictions、editImageFragment 和其他我没有的)
顺便说一句,我不能只在 mainFragment 视图模型存储上调用 clear,因为这里还有其他不应清除的视图模型,我想我想要一种方法来告诉导航主机我知道的父片段应该是什么不是如果我从 mainFragment 或 cardPreviewFragment 导航,这将是一件事,或者一种使视图模型更新的方法
android android-fragments android-viewmodel android-jetpack android-jetpack-navigation
最近我更新了我ViewModel的使用新的viewModelScope. 从它的实现来看,我看到它Dispatchers.Main.immediate被设置CoroutineDispatcher为viewModelScope.
所以当打印当前Thread在viewModelScope.launch它给Thread[main,5,main]
但这是我的问题。尽管它在主线程中运行,但以下代码对我执行网络调用有效。
viewModelScope.launch {
userRepo.login(email, password)
}
Run Code Online (Sandbox Code Playgroud)
这userRepo.login(email, password)是suspend函数,它调用Retrofit suspend函数。
那么这是如何工作的,如果我的当前线程是主线程?
我Transformations.switchMap在我的ViewModel中使用,因此LiveData在我的片段中观察到的我的集合会对code参数的变化做出反应.
这非常有效:
public class MyViewModel extends AndroidViewModel {
private final LiveData<DayPrices> dayPrices;
private final MutableLiveData<String> code = new MutableLiveData<>();
// private final MutableLiveData<Integer> nbDays = new MutableLiveData<>();
private final DBManager dbManager;
public MyViewModel(Application application) {
super(application);
dbManager = new DBManager(application.getApplicationContext());
dayPrices = Transformations.switchMap(
code,
value -> dbManager.getDayPriceData(value/*, nbDays*/)
);
}
public LiveData<DayPrices> getDayPrices() {
return dayPrices;
}
public void setCode(String code) {
this.code.setValue(code);
}
/*public void setNbDays(int nbDays) {
this.nbDays.setValue(nbDays);
}*/
}
public class …Run Code Online (Sandbox Code Playgroud) android observer-pattern android-livedata android-viewmodel android-architecture-components
ActivityViewModel 和惰性 ViewModelProvider 之间的区别?
我见过两种初始化视图模型的方法:
private val someViewModel: SomeViewModel by activityViewModels()
private val someOtherViewModel: SomeOtherViewModel by lazy {
ViewModelProvider(this).get(SomeOtherViewModel::class.java)
}
Run Code Online (Sandbox Code Playgroud)
我知道lazy仅在需要时才初始化 ViewModel,这activityViewModels对于在片段之间共享数据很有用,但除此之外还有什么区别?
Android 文档说其activityViewModels范围仅限于 Activity,但这是否意味着如果在同一 Activity 内的多个片段中使用相同的视图模型,activityViewModels并且只创建一个在所有片段之间共享的实例?
使用 Compose,可以通过以下方式实现“每个屏幕状态”:
NavHost(navController, startDestination = startRoute) {
...
composable(route) {
...
val perScreenViewModel = viewModel() // This will be different from
}
composable(route) {
...
val perScreenViewModel = viewModel() // this instance
}
...
}
Run Code Online (Sandbox Code Playgroud)
“应用程序状态”可以通过以下方式实现:
val appStateViewModel = viewModel()
NavHost(navController, startDestination = startRoute) {
...
}
Run Code Online (Sandbox Code Playgroud)
但是对于“Scoped State”呢?我们如何在 Compose 中实现它?
android android-navigation android-viewmodel android-jetpack-compose
涵盖Android架构组件的最新样本之一是Google提供的GithubBrowserSample.我查看了代码并出现了一些问题:
我注意到ViewModelModule包含在AppModule中.这意味着所有视图模型都被添加到DI图中.为什么以这种方式完成而不是Module为每个只提供ViewModel特定活动/片段所需的活动/片段分开?
在这个具体的例子中,使用GithubViewModelFactory实例化视图模型有没有办法将参数传递给特定的ViewModel?或者更好的解决方案是创建一个setter ViewModel并通过setter设置所需的param?
android dagger dagger-2 android-viewmodel android-architecture-components
最近作为 Kotlin 协程的一部分引入了该类StateFlow。
我目前正在尝试它并在尝试对我的 ViewModel 进行单元测试时遇到问题。我想要实现的目标:测试我StateFlow是否在 ViewModel 中以正确的顺序接收所有状态值。
我的代码如下:
视图模型:
class WalletViewModel(private val getUserWallets: GetUersWallets) : ViewModel() {
val userWallet: StateFlow<State<UserWallets>> get() = _userWallets
private val _userWallets: MutableStateFlow<State<UserWallets>> =
MutableStateFlow(State.Init)
fun getUserWallets() {
viewModelScope.launch {
getUserWallets.getUserWallets()
.onStart { _userWallets.value = State.Loading }
.collect { _userWallets.value = it }
}
}
Run Code Online (Sandbox Code Playgroud)
我的测试:
@Test
fun `observe user wallets ok`() = runBlockingTest {
Mockito.`when`(api.getAssetWallets()).thenReturn(TestUtils.getAssetsWalletResponseOk())
Mockito.`when`(api.getFiatWallets()).thenReturn(TestUtils.getFiatWalletResponseOk())
viewModel.getUserWallets()
val res = arrayListOf<State<UserWallets>>()
viewModel.userWallet.toList(res) //doesn't works
Assertions.assertThat(viewModel.userWallet.value is State.Success).isTrue() //works, …Run Code Online (Sandbox Code Playgroud) android kotlin android-viewmodel kotlin-coroutines kotlin-flow
我已经开始在我的应用程序中使用Architecture Components,我仍然在学习如何使用它.
在我的应用程序中,我有一个活动按顺序显示不同的碎片.在其中一些我需要与后台服务进行通信,以便从外部BLE传感器接收数据.由于我需要在多个片段中与服务进行交互,我想知道ViewModel是否是进行绑定的正确位置.我环顾四周,但没有找到答案.
在ViewModel中绑定服务有什么问题吗?
android android-service android-viewmodel android-architecture-components
我正在尝试通过进行数字增量来将ViewModel与 Jetpack Compose 结合使用。
它不起作用。也许我没有以正确的方式使用 ViewModel。
这是我的活动代码:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting()
}
}
}
@Composable
fun Greeting(
helloViewModel: ViewModel = viewModel()
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
Text(
text = helloViewModel.number.toString(),
fontSize = 60.sp,
fontWeight = FontWeight.Bold
)
Button(onClick = { helloViewModel.addNumber() }) {
Text(text = "Increment Number ${helloViewModel.number}")
}
}
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
AppTheme { …Run Code Online (Sandbox Code Playgroud) android mvvm kotlin android-viewmodel android-jetpack-compose
android ×10
kotlin ×4
android-architecture-components ×3
mvvm ×2
dagger ×1
dagger-2 ×1
kotlin-flow ×1
retrofit ×1