我想类似的设置UI测试GithubBrowserSample,它看起来像示例项目只有模仿ViewModel的Fragment,但不是一个例子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
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\ndata 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}\nRun Code Online (Sandbox Code Playgroud)\n\nRecyclerView 的布局详细信息:
\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
我们如何使用 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) 这就是我正在尝试做的。
ArrayList在 Fragment 内设置对象 FragmentActivity
容器内的观察者获取该数组(承载所有片段的活动)所以,我所做的是以下。
首先,我SharedViewModel从我将设置的位置创建并从中获取数据:
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)
现在,我ViewModel在MainActivity承载所有片段创建的内部实例化它,因此,我可以ArrayData从任何 Fragment 集合中获取它:
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 上做一个.
我正在使用 LiveData 的版本“androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha05”。一旦我的 LiveData 块成功执行,我想明确触发它再次执行,例如
我有一个片段,用于观察我的 LiveData,一个带有 LiveData 和 Repository 的 ViewModel:
视图模型:
Run Code Online (Sandbox Code Playgroud)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()
根据下面的文档,如果 LiveData 块已成功完成,并且如果我在 LiveData 块中放了一个while(true),则不会执行以下文档,然后我的数据会刷新,但是我不希望这样做,因为我需要更新我的反应性地看待。
如果[block]成功完成或由于[LiveData]变为非活动以外的原因被取消,即使[LiveData]经过活动非活动周期后也不会重新执行。
也许我错过了如何重用相同的 LiveDataScope 来实现这一目标?任何帮助,将不胜感激。
android kotlin android-livedata android-viewmodel kotlin-coroutines
多年来,我一直在开发与MVP模式Android应用程序,但现在我正在努力学习MVVM与ViewModel和LiveData
在下面的示例中,我不知道如何根据POST或GET请求传达失败或成功的结果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)
更新:
根据答案和进一步研究,可以使用以下方法:
我正在尝试使用 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 的 Jetpack Compose。
\n对于简单的用例,一切都按预期工作,
\n但我在缺少更高级案例的重组方面遇到了一些麻烦。
我的型号:
\n我正在模拟一个原料存储系统,其中
\ndata class Ingredient(val name: String, @DrawableRes val iconResource: Int? = null)\nRun Code Online (Sandbox Code Playgroud)\ndata class StorageItem(val ingredient: Ingredient, var stock: Int)\nRun Code Online (Sandbox Code Playgroud)\n我的可组合项:
\n我的StorageUi可组合项应该列出所有存储项目
\n并显示成分的图标和名称以及库存。
\n对于这篇文章,我删除了所有不相关的修饰符和格式以简化可读性。
\n(请注意,我使用没有视图模型的第二个版本重载了 StorageScreen 可组合项,
\n是为了更轻松地进行测试并促进 Android Studio 中的预览功能。)
@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
我正在尝试打开一个撰写详细信息页面,其中使用 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) 我对在可组合函数中使用 viewmodel 几乎没有疑问。我正在添加我的活动代码,我正在传递我的意图包。
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
android ×9
kotlin ×6
mvvm ×2
android-architecture-components ×1
android-room ×1
fragment ×1
koin ×1
lazycolumn ×1
mockk ×1