我可以在Fragment中注册MVP Presenter吗?

时间:2017-03-15 20:25:30

标签: android android-fragments android-activity mvp android-mvp

我一直在关注Google提供的MVP设计模式来重构我的应用程序。我有一个MainActivity和许多片段,我为每个片段创建活动似乎很麻烦,所以我一直在考虑在片段中注册演示者。我所看到的是每个片段都注册了它自己的主持人,但我不确定它有多大错...:)

所以这是我的演讲者:

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);
...

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

谢谢你们, BR!

2 个答案:

答案 0 :(得分:18)

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

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

view.setPresenter(T presenter); 

视图方法和Presenters已注册查看。

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

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

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

视图是一个被动接口,它显示数据(模型)并将用户命令(事件)路由到演示者以对该数据进行操作。

因此Activity可以充当overall controller,可以创建PresentersViews并连接它们。

enter image description here

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

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

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

答案 1 :(得分:0)

如果您使用一个活动来托管多个片段,并且还使用Dagger 2插入演示者,则可以将每个演示者直接注入每个片段。

我的用例故事

自从我发现有关Android jetpack导航组件的几个月以来,我一直在做一个带有体系结构的项目,我开始将所有应用程序视图迁移到这种模式。

因此,我在执行该过程时遇到了很多重构,而我处于这种情况,不知道该如何处理。

由于我从一开始就使用Dagger 2将演示者注入到我的“活动”中,因此使用Fragments所做的改变不会太大。

我在同一个存储库中检查了Fragments应该遵循的体系结构,如果您只有1个Fragment,那么这确实是在活动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()
        }
    }
}

如您所见,在这里,我没有导航所需的任何演示者的任何实例化。相反,我只是将我需要的每个演示者注入每个Fragment

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的官方仓库中发现了一个可以帮助我更好地理解它的问题。

您可以here

检查它