标签: android-mvvm

在 MVVM 活动中模拟 ViewModel

29/04/18 更新

重新命名以提高准确性。问题很简单:ViewModels不能简单地在 Activity 上模拟,因为它们是在 Acitivity 的 onCreate() 中实例化的。解决这个问题的最佳方法是什么?

一些相关的想法位于here(未成功尝试实施)

原始问题

使用 Google 的 MVVM GithubBrowserSample 代码库,我正在尝试进行仪器测试以检查加载状态是否会弹出进度条。具体来说,是UserFragmentTest.loading() 方法的镜像。这是非常简单的事情,我试图将我的设置与 Google 的设置紧密匹配。

但是我可以看到这是不对的。具体来说,当我明确要求它们不在我的测试@Before函数中时,我可以看到正在调用我的 ViewModel (VM) 中的函数。我正在使用 Kotlin、Dagger2 和架构组件。

当我运行UserFragmentTest.loading()测试时,我可以看到代码确实在 VM 中没有调用任何东西(甚至没有调用构造函数)。然而BaseActivity,即使我要求它返回虚拟数据,我的也会调用 VM init 块(设置)和 getUser() 函数。我能看到的唯一主要区别是我的 Activity 和 Google 正在测试 Fragment,而 ViewModel 模拟函数使用 Niek Haarman 的Mockito-Kotlin库。

登录活动测试.kt

@RunWith(AndroidJUnit4::class)
class LoginActivityTest {

    private val email = "***********@gmail.com"
    private val password = "123456"

    @Suppress("MemberVisibilityCanBePrivate")
    @get:Rule
    val activityRule = ActivityTestRule(LoginActivity::class.java) …
Run Code Online (Sandbox Code Playgroud)

mockito kotlin android-espresso android-mvvm android-architecture-components

7
推荐指数
0
解决办法
3838
查看次数

在 MVVM 上使用 SharedPreferences 或 File

我很好奇存储库在MVVM架构中的作用。如果您决定将存储库添加到您的项目中,这个存储库是否只负责来自数据库或网络的数据?问题是关于SharedPreferencesor Files,我应该让存储库对此负责,还是应该将它们保留在ViewModel.

sharedpreferences android-mvvm

7
推荐指数
1
解决办法
3736
查看次数

MVVM Dagger2与组件中存在匹配键的绑定

我使用以下谷歌示例项目:https://github.com/googlesamples/android-architecture-components作为我的新项目的参考,并且在尝试向项目添加第二个活动时遇到困难.

这是编译时遇到的错误

Error:(22, 8) error: [dagger.android.AndroidInjector.inject(T)] com.apps.myapp.ui.common.MainActivity cannot be provided without an @Inject constructor or from an @Provides-annotated method. This type supports members injection but cannot be implicitly provided.
com.apps.myapp.ui.common.MainActivity is injected at
com.apps.myapp.ui.common.NavigationController.<init>(mainActivity)
com.apps.myapp.ui.common.NavigationController is injected at
com.apps.myapp.ui.addContacts.AddContactsFragment.navigationController
com.apps.myapp.ui.addContacts.AddContactsFragment is injected at
dagger.android.AndroidInjector.inject(arg0)
A binding with matching key exists in component: com.apps.myapp.di.ActivityModule_ContributeMainActivity.MainActivitySubcomponent
Run Code Online (Sandbox Code Playgroud)

这是我的代码

ActivityModule

@Module
public abstract class ActivityModule {

    @ContributesAndroidInjector(modules = FragmentBuildersModule.class)
    abstract MainActivity contributeMainActivity();

    @ContributesAndroidInjector(modules = FragmentBuildersModule.class)
    abstract ContactActivity contributeContactActivity();
} 
Run Code Online (Sandbox Code Playgroud)

AppComponent

@Singleton …
Run Code Online (Sandbox Code Playgroud)

android mvvm dagger-2 android-mvvm android-architecture-components

6
推荐指数
1
解决办法
2910
查看次数

从MVVM架构中的ViewModel启动Activity的最佳方法

我在app中关注MMVM架构,Everything工作正常,直到我使用以下代码从ViewModel启动活动时崩溃.使用数据绑定从XML调用方法并将其view作为参数传递,并且getApplication()AndroidViewModel类中的方法.

getApplication().startActivity(new Intent(view.getContext(), MyActivity.class));
Run Code Online (Sandbox Code Playgroud)

我相信这是因为我没有使用NEW_TASK标志,因为我在Activity类之外开始活动.

现在有以下解决方案我可以想到但不确定哪一个最好基于架构观点.

1. ViewModel,其方法采用Activity参数并从片段中调用该方法

public startMyActivity(Activity activity){
   activity.startActivity(new Intent(activity, MyActivity.class));
}
Run Code Online (Sandbox Code Playgroud)

现在在片段中添加类似这样的列表器

mBinding.myButton.setOnClickListener(){
    viewModel.startMyActivity(getActivity());  
}
Run Code Online (Sandbox Code Playgroud)

2.向intent添加一个New Task标志并将其保存在ViewModel本身中

Intent myIntent = new Intent(view.getContext(), MyActivity.class);
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
getApplication().startActivity(myIntent);
Run Code Online (Sandbox Code Playgroud)

3.从片段本身启动Activity

mBinding.myButton.setOnClickListener(){
   activity.startActivity(new Intent(activity, MyActivity.class));
}
Run Code Online (Sandbox Code Playgroud)

我相信所有这些方法都很好,但是一个问题

是否可以在Fragment中分别使用绑定的ViewModel从view xml调用方法?

我不确定第二种方法,如果这仍然会在某些操作系统中崩溃应用程序.

从架构的角度和单元测试的角度来看哪一个是最好的方法?

android mvvm android-mvvm android-viewmodel

6
推荐指数
1
解决办法
3269
查看次数

Android MVVM-如何使LiveData发出其拥有的数据(强制触发观察者)

我有ViewModel从网络获取列表的列表,并RecyclerView用数据填充了a (MyAvailabilityRepository返回a MutableLiveData,这就是我正在使用的原因Transformations.switchMap):

class MyAvailabilityViewModel : ViewModel() {
    private val getListsParams = MutableLiveData<String>()
    private val getListsObservable = Transformations.switchMap(getListsParams) { 
        organizationId -> MyAvailabilityRepository.getSectionedLists(organizationId) 
    }

    fun getListsObservable() : LiveData<Resource<MutableList<SectionedAvailabilityList>>> {
        return getListsObservable
    }

    fun fetchLists(organizationId: String, forceRefresh: Boolean = false) {
        if (getListsParams.value == null || forceRefresh) {
            getListsParams.value = organizationId
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

片段的onActivityCreated

override fun onActivityCreated(savedInstanceState: Bundle?) {
    ...
    viewModel.getListsObservable().observe(this, Observer { // populate RecyclerView })
    viewModel.fetchLists(organizationId)
}
Run Code Online (Sandbox Code Playgroud)

由于 …

android android-mvvm android-livedata android-architecture-components

6
推荐指数
2
解决办法
1183
查看次数

带有 MVVM 的 RxJava:带有 setValue() 的 MutableLiveData 与 LiveDataReactiveStreams

Let's say you have a MVVM app with a UI layer, a ViewModel, and a Repository. Say that in your repository, you're getting some data from an API with Single Retrofit calls, and transforming it into a UI-ready viewstate object.

The way I see it, you have two main choices (assuming you want to use LiveData in the UI layer, I am not including the option of observing Rx types from the UI):

  1. Expose your Rx Observable from the repository, …

android android-mvvm rx-java2 android-livedata

6
推荐指数
0
解决办法
423
查看次数

在 android mvvm 架构中使用位置 api 的正确位置

我有一个场景,我想显示用户当前的天气数据,因为我正在获取他/她当前的纬度/经度并对其进行反向地理编码以获取城市名称。获得城市名称后,我将拨打网络电话并显示天气数据。除此之外,我还需要执行许多位置操作。

所以我创建了一个名为LocationUtils.kt. 我遵循 MVVM 架构,想知道哪个是调用LocationUtils方法的理想层,是view层还是viewmodel层还是data层。由于FusedLocationProvider需要context,如果我在ViewModel其中使用它会泄漏。那么如何解决这个问题呢?

LocationUtils.kt

class LocationUtils {
  private lateinit var fusedLocationClient: FusedLocationProviderClient

  private fun isLocationEnabled(weakContext: Context?): Boolean {
    return when {
      Build.VERSION.SDK_INT >= Build.VERSION_CODES.P -> {
        // This is new method provided in API 28
        val locationManager = weakContext?.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        locationManager.isLocationEnabled
      }
      Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> {
        // This is Deprecated in API 28
        val mode = Settings.Secure.getInt(
            weakContext?.contentResolver, Settings.Secure.LOCATION_MODE, …
Run Code Online (Sandbox Code Playgroud)

android android-mvvm

6
推荐指数
1
解决办法
1372
查看次数

使用 livedata 进行 Android 视图模型单元测试

我正在对我的视图模型进行单元测试,并且我总是不断地获得NullPointerException.

这是我的视图模型代码 -

class LoginViewModel(private val myUseCase: MyUseCase) :BaseViewModel() {

    private val viewState = LoginViewState()

    fun onLoginClicked() =
        Transformations.map(
            myUseCase.performUseCaseAction(
                MyAction.LoginUser(
                    email,password)
            )
        ) {
            when (it) {
                is MyResult.Loading -> viewState.copy(loading = true)
                is MyResult.UserLoggedIn -> viewState.copy(
                    loading = false,
                    userLoggedIn = true
                )
                is MyResult.Error -> viewState.copy(loading = false, error = it.error)
            }
        }
}
Run Code Online (Sandbox Code Playgroud)

这是 MyUseCase 接口代码 -

interface MyUseCase {

    fun performUseCaseAction(action: MyAction): LiveData<MyResult>
}
Run Code Online (Sandbox Code Playgroud)

这是相同的单元测试 -

@RunWith(MockitoJUnitRunner::class)
class LoginViewModelTest {

    @get:Rule
    val instantExecutorRule …
Run Code Online (Sandbox Code Playgroud)

junit android kotlin android-mvvm kotlin-coroutines

6
推荐指数
1
解决办法
2994
查看次数

在 Android 上使用 MVVM 模式时从一个片段导航到另一个片段

  • 我正在使用 MVVM 模式创建一个应用程序。我使用导航图来管理应用程序中的片段,根据推荐的方法,我们不必将 UI 逻辑放在Activity/Fragments中,而是放在Viewmodel中。

  • 所以我的问题是如何从一个片段导航到另一个片段。我知道这可以直接在片段内部完成,navController.navigate(R.id.action_here)但是我将如何在按下按钮时处理 ViewModel 的导航?

我的代码:

IntroViewModel.kt

class IntroViewModel : ViewModel() {

    fun onBtn1Pressed(view: View) {
        Log.d(IntroViewModel::class.java.simpleName, ": onBtn1Pressed")
    }

    fun onBtn2Pressed(view: View) {
        Log.d(IntroViewModel::class.java.simpleName, ": onBtn2Pressed ")
    }
}
Run Code Online (Sandbox Code Playgroud)

IntroFragment.kt:

class IntroFragment : Fragment() {

    private lateinit var viewModel: IntroViewModel
    private lateinit var navController: NavController
    lateinit var introBinding: IntroFragmentBinding

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        introBinding = DataBindingUtil.inflate(inflater, R.layout.intro_fragment, container, false)
        viewModel = ViewModelProviders.of(this).get(IntroViewModel::class.java) …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-mvvm android-jetpack

6
推荐指数
1
解决办法
5632
查看次数

通过视图模型和使用工厂创建视图模型之间的区别?

我正在研究ViewModel将其应用到MVVM设计模式中。

有一个使用方法by viemodels()和一个ViewModelProvider.Factory在视图模型创建中使用的方法。

by viewModels()创建一个ViewModel object.

ViewModelProvider.Factory还创建Viewmodel objects.

这两者有什么区别?

另外,在一些示例代码中,我看到注释中的代码3,其中使用了by viewModels()and factory。这是什么意思?

class WritingRoutineFragment : Fragment() {
    private val viewModel: WriteRoutineViewModel by viewModels() // 1
    private lateinit var viewModelFactory: WriteRoutineViewModelFactory

//  private val viewModel: WriteRoutineViewModel by viewModels(
//        factoryProducer = { viewModelFactory } // 3.What does this code mean?
//  )

    override fun onCreateView(inflater: LayoutInflater,
                              container: ViewGroup?,
                              savedInstanceState: Bundle?): View? { …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-mvvm android-viewmodel

6
推荐指数
1
解决办法
4747
查看次数