12

我一直在遵循Google提供的 MVP 设计模式 来重构我的应用程序。我有一个 MainActivity 和许多 Fragments,为每个 Fragment 创建一个 Activity 对我来说似乎并不麻烦,所以我一直在考虑在 Fragment 中注册 Presenter。我看到的是每个片段都注册了自己的演示者,但我不确定它有多大的错误...... :)

所以这是我的演示者:

public class FirstPresenter implements FirstContract.Presenter {
    private final FirstContract.View mView;

    public FirstPresenter(FirstContract.View view) {
        mView = view;
    }

    @Override
    public void start() {
        Log.e(TAG, "Start");
    }
}

这是我的片段:

public class FirstFragment extends Fragment implements FirstContract.View {
    private FirstContract.Presenter mPresenter;

@Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container
            , Bundle savedInstanceState) {
...
// I register firstFragment's presenter here.
mPresenter = new FirstPresenter(this);
...

所以我的问题是,这是正确的方法吗?我可以在 Activity 中将 Presenter 注册到 Fragment 吗?如果这不是正确的方法,是否有一些很好的例子来处理具有一个活动和多个片段的 MVP?

谢谢你们,BR!

4

2 回答 2

19

正如您在Google 的示例 ( https://github.com/googlesamples/android-architecture ) 中看到的,Activities创建Presenters. 还Views附加到ActivityPresenters获取视图 ( Fragments) 作为参数。

Fragment事务提交或Fragment(视图)状态恢复后Presenters创建并以Fragments(视图)作为参数而不是调用

view.setPresenter(T presenter); 

查看方法并Presenters注册查看。

我认为创作不是一个好习惯PresenterFragment首先,它们是独立的层这对于分离关注点是非法的。其次,如果您在 中创建演示者,则将Fragment演示者的生命绑定到视图的生命LifeCycle,当Fragment被销毁和重新创建时,您将创建一个新的演示者,但它们是不同的层。

模型是定义要在用户界面中显示或以其他方式操作的数据的界面。

演示者作用于模型和视图。它从存储库(模型)中检索数据,并将其格式化以在视图中显示。

视图是一个被动界面,它显示数据(模型)并将用户命令(事件)路由到演示者以对该数据采取行动。

所以Activity可以充当overall controller创建和连接它们的Presenters角色Views

在此处输入图像描述

如果我们谈论您的问题,是的,您可以在片段中注册演示者。但是您应该避免在用作视图的片段中创建演示者。

但是在 Android 社​​区中有很多关于 MVP 模式的不同方法,如下所示。 https://plus.google.com/communities/114285790907815804707

为什么活动不是ui元素? http://www.techyourchance.com/activities-android/

于 2017-03-15T21:23:37.797 回答
2

如果您使用一个 Activity 来托管多个 Fragment,并且您还使用 Dagger 2 来注入您需要的 Presenter,您可以将每个 Presenter 直接注入每个 Fragment。

我的用例故事

自从我发现 Android jetpack Navigation Component 几个月后,我开始做一个架构项目,我开始将我所有的应用程序视图迁移到这种模式中。

所以,我在做这个过程时遇到了很多重构,我当时不知道如何处理这种情况。

由于我从一开始就使用 Dagger 2 将我的演示者注入到我的活动中,所以这样做不会有太大变化,但使用 Fragments。

我遇到了同一个存储库来检查架构应该如何与 Fragments 一起使用,如果您小时候只有 1 个 Fragment,这确实是在主机 Activity 中进行演示者实例化的好方法。

问题是,如果我需要在一个主机 Activity 中有多个片段,我应该为每个演示者创建一个实例,并将其通过每个片段中的 FragmentManager 传递,我认为这不是我所看到的,因为它添加了来自主持人活动的演示者。

这会导致一种情况,在我的主机活动中为所有演示者提供多个实例,以及一些接口来处理作业/视图的分离(如果需要)。

使用多个片段执行此操作的一种简单方法是不考虑主机活动并将演示者注入每个片段本身。

由于使用 Dagger 执行此操作,它使注入更清洁。

看一个简单的例子

class MainMenuActivity : BaseActivity(){

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        inflateMainFragment(savedInstanceState)
    }

      override fun getLayout(): Int {
        return R.layout.activity_main_menu
    }

    fun inflateMainFragment(savedInstanceState: Bundle?){
        if (savedInstanceState == null) {
            val fragment = MainMenuFragment()
            supportFragmentManager
                .beginTransaction()
                .add(R.id.nav_host_fragment, fragment)
                .commit()
        }
    }
}

正如你所看到的,在这里我没有任何我的导航应该需要的任何演示者的实例化。相反,我只是在每个片段中注入我需要的每个演示者

class MapsFragment: BaseMapFragment(), MapContract.MapView {

    private lateinit var mMap: GoogleMap

    @Inject
    lateinit var presenter: MapsPresenter

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_paseo,container,false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (requireActivity().application as YawpApplication).getAppComponent()?.inject(this)
        presenter.attachView(this)
        setupToolbar()
        setupMap()
    }
}

并且利用 Fragments 生命周期,您可以在onDestroyView()方法中分离所有 Fragments 视图,并在垃圾收集器运行时节省一些内存空间。

 override fun onDestroyView() {
        super.onDestroyView()
        presenter.detachView()
        presenter.detachJob()
    }

我在官方 google repo 中发现了一个帮助我更好地理解它的问题。

你可以在这里查看

于 2019-07-19T23:45:10.540 回答