我可以在 Fragment 中注册 MVP Presenter

Can I register MVP Presenter inside Fragment

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

这是我的主持人:

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 中吗?如果这不是正确的方法,是否有一些很好的例子来处理一个 activity 和多个片段的 MVP?

谢谢大家, BR!

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

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

view.setPresenter(T presenter); 

查看方法和Presenters注册查看。

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

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

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

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

所以 Activity 可以作为一个 overall controller 创建 PresentersViews 并连接它们。

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

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

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

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

我的用例故事

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

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

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

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

问题是,如果我需要在一个主机中有多个片段 Activity 我应该为每个演示者创建一个实例,并通过每个片段中的 FragmentManager 传递它,我认为这不是我想要的正在查看,因为它从主机 Activity.

添加了演示者的多个实例

这导致一种情况,在我的主机中有多个实例 activity 供所有演示者使用,还有一些接口可以在需要时处理 jobs/views 的分离。

使用多个片段来做到这一点的一种简单方法就是不考虑主机 activity 并将演示者注入每个片段本身。

自从使用 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 视图,并在垃圾收集器运行时节省一些内存 space。

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

我在官方 google 回购中找到了一个问题,帮助我更好地理解它。

你可以看看here