Android架构组件中每个组件的责任问题

8

我已经使用MVP很长时间了,现在开始转向MVP和MVVM之间的混合状态。

具体来说,我的应用程序将如下所示:

  • 每个Activity都有0到x个Fragment代表其视图
  • 每个Fragment将请求Activity的ViewModel以便使用LiveData检索数据
  • Activity将拥有一个单独的ViewModel,作为Presenter。在创建时,该ViewModel将被注入活动的ViewModel和LiveData,以便根据需要更新UI
  • Presenter将获取发送到数据ViewModel的消息并将结果发送回去

我的问题:

  1. 在Presenter ViewModel中持有对数据ViewModel的引用会导致内存泄漏或其他不良影响吗?
  2. 业务逻辑应该放在Presenter还是模型部分中?

例如,假设我有一个项目列表,用户长按一个项目以编辑它们,这个架构的哪个部分应该负责检查用户是否有权限这样做,并允许他们编辑该项目或显示错误消息?

  1. 是否有一种方法使Fragment只获取Activity的ViewModel的一部分?

例如,假设活动下有3个片段,并且一个ViewModel来迎合它们

我可以使用类似于:

class MainViewModel : ViewModel() , IFragmentA, IFragmentB, IFragmentC

当我尝试在片段中获取ViewModel时,可以写出以下代码:

lateinit var viewModel: IFragmentA

override fun onAttach(context: Context?) {
    super.onAttach(context)
    vm = ViewModelProviders.of(context as AppCompatActivity).get(IFragmentA::class.java)
}

注意:我知道上面的代码不起作用,我的问题是是否有一种类似于这样的方法可以起作用。

  1. 发送消息回SingleEvents活动的正确方式是什么?

例如,如果用户尝试删除某个条目,并且我希望他们输入密码,流程是否如下:

  • 片段将删除消息发送到其ViewModel
  • ViewModel将其传递给Presenter
  • Presenter决定在继续之前需要密码验证
  • Presenter在ViewModel中设置SingleEvent的值
  • ViewModel通知事件的订阅者(在这种情况下为MainActivity)显示一个对话框,要求输入密码

感谢您能提供的任何帮助。


我宁愿不要将其做成混合型,你应该完全转向MVVM或者继续使用MVP - Jeel Vankhede
@Cruces,你在你的项目中使用Dagger吗? - HourGlass
@JeelVankhede 是的,我也倾向于这条路线,但我还不确定,我会在几个应用程序中尝试一下,看看效果如何。 - Cruces
@HourGlass 不,我不是这样做的,我通过构造函数调用来进行注入,当我更熟练于MVVM时,我会开始学习和使用Dagger。 - Cruces
1个回答

6
我最近将我的一个应用从MVP架构迁移到了MVVM架构。无论你是部分或完全实现,你都在朝着更好、更干净的方向迈进,你会喜欢它。
在查看答案之前,请先看一下这个MVVM架构图和一些注意事项。

MVVM Architecture

让我们来看看这里每个类的角色。

Activity/Fragment:

-听取MutableLiveData观察者并将数据设置到视图中,在此没有其他逻辑。

ViewModel

  • 用户输入验证(用户名、密码为空或null检查)
  • 设置您的mutableLive
  • 要求存储库启动任务网络或本地数据存储(sqlite),并带有回调。

Repository

  • 缓存所需数据。
  • 不应持有任何对ViewModel的引用,这将创建循环依赖关系。
  • 决定要做什么——是进行网络调用还是从本地存储加载数据。在此处进行接收到的数据操作(业务逻辑)。
  • 使用从ViewModel收到的回调将数据更新到viewModel,严格禁止直接通信。

RemoteDataSource

  • 进行网络调用并将收到的数据返回给存储库。

LocalDataSource

  • 处理所有与SQLite相关的内容,并通过回调提供请求的数据。

有一个来自谷歌的todo app示例项目,它使用了MVVM。请参考它,这将非常有帮助。

  1. 没有Presenter - 在ViewModel中检查用户输入,并使用Repository向前通信,使用MutableLiveData向后通信。
  2. 在Repository中进行业务逻辑,将其视为MVP模式中的模型。
  3. 您可以为活动及其片段拥有单个ViewModel。所有片段通过一个ViewModel进行通信。因此,每个片段仅会对其侦听的LiveDataObserver做出反应。

实际上,在Google的MVVM示例项目中,有一个关于此用例的示例。

AddEditTaskActivity.java

public static AddEditTaskViewModel obtainViewModel(FragmentActivity activity) {
       // Use a Factory to inject dependencies into the ViewModel        
 ViewModelFactoryfactory= ViewModelFactory.getInstance(activity.getApplication());
 return ViewModelProviders.of(activity, factory).get(AddEditTaskViewModel.class);
   }

AddEditTaskFragment.java

 @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final View root = inflater.inflate(R.layout.addtask_frag, container, false);
        if (mViewDataBinding == null) {
            mViewDataBinding = AddtaskFragBinding.bind(root);
        }

        mViewModel = AddEditTaskActivity.obtainViewModel(getActivity());

        mViewDataBinding.setViewmodel(mViewModel);
        mViewDataBinding.setLifecycleOwner(getActivity());

        setHasOptionsMenu(true);
        setRetainInstance(false);

        return mViewDataBinding.getRoot();
    }


4. 密码验证流程:
- 片段请求ViewModel删除Entry。 - 请求仓库决定是否需要验证,使用已有数据或与本地数据源通信。 - ViewModel从Repository接收回调,表示需要验证,ViewModel更新相应的MutableLiveData showVerification.postValue(true)。 - 由于Activity正在监听showVerificationObserver,因此它会显示验证UI。
希望这可以帮到您。

在我的规格说明中,我所称呼的 presenter 似乎就是你所说的 repository,因为在我的想法中,我希望使用的 presenter 能够完成这些任务(决定要调用谁、工作流程是什么等等)。感谢提供项目链接,看起来很有趣,我一定会阅读并尝试你的解决方案,看看它对我是否有效。 - Cruces
数据的处理(业务逻辑)应该放在这里。我认为这不是存储库的责任,而应该由视图模型或用例来处理? - Sharp Edge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接