标签: android-viewmodel

Android架构组件ViewModel - 如何在测试Activity上模拟ViewModel?

我想类似的设置UI测试GithubBrowserSample,它看起来像示例项目只有模仿ViewModelFragment,但不是一个例子Activity.

这是我的代码,我试图Activity通过嘲笑来测试ViewModel.但是在Activity ViewModel之前没有设置好onCreate().

@RunWith(AndroidJUnit4::class)
class MainActivityTest {

    val viewModel = mock(MainViewModel::class.java)

    @Rule
    @JvmField
    val activityRule = ActivityTestRule<MainActivity>(MainActivity::class.java, true, true)

    private val liveData = MutableLiveData<Resource<Object>>()

    @Before
    open fun setUp() {
        activityRule.activity.viewModelFactory = createViewModelFor(viewModel)
        `when`(viewModel.liveData).thenReturn(liveData)
        viewModel.liveData?.observeForever(mock(Observer::class.java) as Observer<Resource<Object>>)
        liveData.postValue(Resource.success(Object()))
    }

    fun <T : ViewModel> createViewModelFor(model: T): ViewModelProvider.Factory =
        object : ViewModelProvider.Factory {
            override fun <T : ViewModel> create(modelClass: Class<T>): T {
                if (modelClass.isAssignableFrom(model.javaClass)) {
                    return model as …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-espresso android-viewmodel android-architecture-components

8
推荐指数
1
解决办法
1148
查看次数

双向数据绑定、RecyclerView、ViewModel、Room、LiveData、Oh My

Android 开发新手,我\xe2\x80\x99m 试图将我的注意力集中在与 RecyclerView、ViewModel、Room 和 LiveData 结合的双向数据绑定上。我理解单向绑定,但不能\xe2\x80\x99t 找出双向。

\n\n

简而言之,我\xe2\x80\x99d 希望能够点击 id/switch_enabled 开关并更新 Db 以反映这一点(然后我计划利用它来更新类/Db 中的其他成员)。我认为我需要一些帮助来设置 ViewModel 上的 set(value) 并在 Db 中更新正确的 RecyclerView 项目,但我\xe2\x80\x99m 不确定如何执行此操作,或者这是否是正确或最佳的方法。

\n\n

谢谢。

\n\n

班级:

\n\n
data class Person (@ColumnInfo(name = "first_name") val firstName: String,\n                   @ColumnInfo(name = "last_name") val lastName: String,\n\n                   //...\n\n                   val enabled: Boolean = true\n){\n    @PrimaryKey(autoGenerate = true)\n    var id: Long = 0\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

RecyclerView 的布局详细信息:

\n\n
<layout xmlns:android="http://schemas.android.com/apk/res/android"\n    xmlns:app="http://schemas.android.com/apk/res-auto"\n    xmlns:tools="http://schemas.android.com/tools">\n\n    <data>\n        <variable\n            name="p" type="com.example.data.Person" />\n    </data>\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:id="@+id/constraintLayout"\n        android:layout_width="match_parent"\n        android:layout_height="wrap_content">\n\n        <TextView\n            android:id="@+id/first_name"\n            android:layout_width="wrap_content"\n …
Run Code Online (Sandbox Code Playgroud)

android-recyclerview android-databinding android-room android-livedata android-viewmodel

8
推荐指数
1
解决办法
5184
查看次数

如何在 Kotlin 中使用 Koin 注入 ViewModel?

我们如何使用 Koin 为 ViewModel 注入依赖项?

所以例如,我有一个ViewModel这样的:

class SomeViewModel(val someDependency: SomeDependency, val anotherDependency: AnotherDependency): ViewModel()
Run Code Online (Sandbox Code Playgroud)

现在这里的官方文档指出,要提供一个ViewModel我们可以执行以下操作:

val myModule : Module = applicationContext {

    // ViewModel instance of MyViewModel
    // get() will resolve Repository instance
    viewModel { SomeViewModel(get(), get()) }

    // Single instance of SomeDependency
    single<SomeDependency> { SomeDependency() }

    // Single instance of AnotherDependency
    single<AnotherDependency> { AnotherDependency() }
}
Run Code Online (Sandbox Code Playgroud)

然后注入它,我们可以这样做:

class MyActivity : AppCompatActivity(){

    // Lazy inject SomeViewModel
    val model : SomeViewModel by viewModel()

    override fun …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-viewmodel koin

8
推荐指数
1
解决办法
4442
查看次数

ViewModelProviders 在我的 Fragment 中不起作用

这就是我正在尝试做的。

  • ArrayList在 Fragment 内设置对象
  • FragmentActivity 容器内的观察者获取该数组(承载所有片段的活动)

所以,我所做的是以下。

首先,我SharedViewModel从我将设置的位置创建并从中获取数据:

共享视图模型.kt

class SharedViewModel: ViewModel() {

    var personArrayObj:MutableLiveData<ArrayList<Person>> = MutableLiveData()

    fun setPersonArray(personArray:ArrayList<Person>){
        personArrayObj.value = personArray
    }

    val getPersonArray:LiveData<ArrayList<Person>>
    get() = personArrayObj

}
Run Code Online (Sandbox Code Playgroud)

现在,我ViewModelMainActivity承载所有片段创建的内部实例化它,因此,我可以ArrayData从任何 Fragment 集合中获取它:

主活动.kt

class MainActivity: FragmentActivity(){

private lateinit var viewModel:SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        viewModel = ViewModelProviders.of(this).get(SharedViewModel::class.java)
        viewModel.getPersonArray.observe(this, Observer { it:ArrayList<Person>
            Log.d("Array:",""+it)
        })
    }

}
Run Code Online (Sandbox Code Playgroud)

然后我需要做的最后一件事是从我想要的任何 Fragment 设置该 Array 的值,然后如果该值发生更改,将触发主机 Activity,因此,要做到这一点,我只需viewModel.setValue(personArray)在我想要的Fragment 上做一个.

问题 …

android mvvm fragment kotlin android-viewmodel

8
推荐指数
1
解决办法
1万
查看次数

如何再次调用 LiveData 协程块

我正在使用 LiveData 的版本“androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha05”。一旦我的 LiveData 块成功执行,我想明确触发它再次执行,例如

  1. 我导航到一个片段
  2. 用户数据加载
  3. 我在同一个片段中单击删除 btn
  4. 用户的数据应该刷新

我有一个片段,用于观察我的 LiveData,一个带有 LiveData 和 Repository 的 ViewModel:

视图模型:

  fun getUserLiveData() = liveData(Dispatchers.IO) {

   val userData = usersRepo.getUser(userId)

   emit(userData) 
}
Run Code Online (Sandbox Code Playgroud)

分段:

viewModel.getUserLiveData.observe(viewLifecycleOwner,
            androidx.lifecycle.Observer {.. 
Run Code Online (Sandbox Code Playgroud)

然后我试图实现这样的期望行为:

viewModel.deleteUser()

viewModel.getUserLiveData()
Run Code Online (Sandbox Code Playgroud)

根据下面的文档,如果 LiveData 块已成功完成,并且如果我在 LiveData 块中放了一个while(true),则不会执行以下文档,然后我的数据会刷新,但是我不希望这样做,因为我需要更新我的反应性地看待。

如果[block]成功完成由于[LiveData]变为非活动以外的原因被取消,即使[LiveData]经过活动非活动周期后也不会重新执行。

也许我错过了如何重用相同的 LiveDataScope 来实现这一目标?任何帮助,将不胜感激。

android kotlin android-livedata android-viewmodel kotlin-coroutines

8
推荐指数
1
解决办法
3144
查看次数

当 Retrofit 请求失败或成功时,如何在 Repository 和 ViewModel 类之间进行通信?

多年来,我一直在开发与MVP模式Android应用程序,但现在我正在努力学习MVVMViewModelLiveData

在下面的示例中,我不知道如何根据POSTGET请求传达失败或成功的结果Retrofit

与MVP之前,我将与使用侦听器与任何沟通主持人listener.onTodoFetched()listener.onTodoFetchError()反应,然后根据不同的哪个方法被调用。我还应该以这种方式与ViewModel班级交流吗?

获取TodoRepository.java

public MutableLiveData<String> fetchTodo() {
    retrofitService.getRetrofitService().create(Endpoints.class).getTodo().enqueue(new Callback<String>() {
        @Override
        public void onResponse(Call<String> call, Response<String> response) {

            if (response.isSuccessful() && response.body() != null) {
                listener.onTodoFetched(response.body());     //ViewModel equivalent?
            } else {
                listener.onTodoFetchError(response.message());     //ViewModel equivalent?
            }

        }

        @Override
        public void onFailure(Call<String> call, Throwable t) {
            listener.onTodoFetchError(t.getMessage());     //ViewModel equivalent?
        }
    });

    return mutableLiveData;
}
Run Code Online (Sandbox Code Playgroud)

更新:

根据答案和进一步研究,可以使用以下方法:

  • 类之间的普通 Java 侦听器
  • RxJava
  • Kotlin 高阶函数。

android mvvm android-livedata android-viewmodel

8
推荐指数
1
解决办法
2423
查看次数

MockK模拟ViewModel的savedStateHandle.getLiveData()

我正在尝试使用 saveStateHandle 测试此 ViewModel

class PostListViewModel @ViewModelInject constructor(
    private val coroutineScope: CoroutineScope,
    private val getPostsUseCase: GetPostListUseCaseFlow,
    @Assisted savedStateHandle: SavedStateHandle
) : AbstractPostListVM() {

    private val _goToDetailScreen =
        savedStateHandle.getLiveData<Event<Post>>(POST_DETAIL)
//        MutableLiveData<Event<Post>>()

    override val goToDetailScreen: LiveData<Event<Post>>
        get() = _goToDetailScreen

    private val _postViewState =
        savedStateHandle.getLiveData<ViewState<List<Post>>>(POST_LIST)
//        MutableLiveData<ViewState<List<Post>>>()

    override val postViewState: LiveData<ViewState<List<Post>>>
        get() = _postViewState

    override fun getPosts() {

        getPostsUseCase.getPostFlowOfflineFirst()
            .convertToFlowViewState()
            .onStart {
                _postViewState.value = ViewState(status = Status.LOADING)
            }
            .onEach {
                _postViewState.value = it
            }
            .launchIn(coroutineScope)
    }

    override fun refreshPosts() {
        getPostsUseCase.getPostFlowOfflineLast()
            .convertToFlowViewState()
            .onStart …
Run Code Online (Sandbox Code Playgroud)

android android-livedata android-viewmodel mockk

8
推荐指数
2
解决办法
5960
查看次数

Jetpack Compose:更新列表元素内容时不会发生重组

我正在尝试 Android 的 Jetpack Compose。
\n对于简单的用例,一切都按预期工作,
\n但我在缺少更高级案例的重组方面遇到了一些麻烦。

\n

我的型号

\n

我正在模拟一个原料存储系统,其中

\n
    \n
  • 成分由名称和可选图标组成
  • \n
\n
data class Ingredient(val name: String, @DrawableRes val iconResource: Int? = null)\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • StorageItem由成分和库存(该成分的存储量)组成
  • \n
\n
data class StorageItem(val ingredient: Ingredient, var stock: Int)\n
Run Code Online (Sandbox Code Playgroud)\n

我的可组合项

\n

我的StorageUi可组合项应该列出所有存储项目
\n并显示成分的图标和名称以及库存。
\n对于这篇文章,我删除了所有不相关的修饰符和格式以简化可读性。
\n(请注意,我使用没有视图模型的第二个版本重载了 StorageScreen 可组合项,
\n是为了更轻松地进行测试并促进 Android Studio 中的预览功能。)

\n
    @Composable\n    fun StorageScreen(viewModel: StorageViewModel) {\n        StorageScreen(\n            navController = navController,\n            storageItems = viewModel.storageItems,\n            onIngredientPurchased = viewModel::purchaseIngredient\n        )\n    }\n\n    @Composable\n …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-viewmodel android-jetpack-compose lazycolumn

8
推荐指数
1
解决办法
8191
查看次数

Viewmodel 在 Compose 中实例化,并多次调用 hiltviewmodel()

我正在尝试打开一个撰写详细信息页面,其中使用 hiltviewmodel() 添加了 Viewmodel 该视图模型具有分页数据状态和 API 调用结果状态,需要它来显示更新的数据以及列表。但是当我导航到详细信息页面时,viewmodel 方法被多次调用,甚至 init {} 块也被调用。有人遇到过类似的问题吗,或者有什么解决办法吗?

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun DashboardScreen(
    navController: NavController,
    dashboardViewModel: DashboardViewModel = hiltViewModel(),
    Name: String = ""
) {
    val lazyArticleList = dashboardViewModel.articlePages.collectAsLazyPagingItems()
    val dashState = dashboardViewModel.dashboardState.value
}
Run Code Online (Sandbox Code Playgroud)

android android-viewmodel android-jetpack-compose

8
推荐指数
1
解决办法
2057
查看次数

在jetpack compose中使用视图模型的最佳实践

我对在可组合函数中使用 viewmodel 几乎没有疑问。我正在添加我的活动代码,我正在传递我的意图包。

  1. 所以我想问使用这样的视图模型viewmodel在活动中创建全局是最佳实践吗?

输入活动.kt

class InputActivity : ComponentActivity() {

    private val viewModel by viewModel<InputViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setupViewModel()
        setContent {
            Theme {
                AppBarScaffold(
                    displayHomeAsUpEnabled = true,
                    titleId = R.string.personal_health
                ) {
                    viewModel.OptionData?.let {
                        Input(it)
                    }
                }
            }
        }
    }

    private fun setupViewModel() {
        viewModel.optionData = intent.getParcelableExtra("optiondata")
    }
}
Run Code Online (Sandbox Code Playgroud)

我有很多可组合的函数

输入

@Composable
fun Input(optionData: OptionData) {
    var value by rememberSaveable {
        mutableStateOf(false)
    }
    Column(
        modifier = Modifier
            .fillMaxHeight()
            .verticalScroll(rememberScrollState())
        verticalArrangement = Arrangement.SpaceBetween
    ) {
        InputItem() …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-viewmodel android-jetpack android-jetpack-compose

8
推荐指数
1
解决办法
1万
查看次数