我可以在 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
附加到 Activity
和 Presenters
获取视图 (Fragments
) 作为参数。
在 Fragment
事务提交或 Fragment
(视图)状态恢复后 Presenters
被创建并以 Fragments
(视图)作为参数而不是调用
view.setPresenter(T presenter);
查看方法和Presenters
注册查看。
我认为在 Fragment
中创建 Presenter
不是一个好的做法。首先,它们是 独立的层 。这对于 关注点分离 是非法的。其次,如果您在 Fragment
中创建演示者,则将演示者的生命绑定到视图的 LifeCycle
,当 Fragment
被销毁并重新创建时,您将创建一个新的演示者,但它们是不同的层。
模型 是定义要在用户界面中显示或以其他方式操作的数据的界面。
presenter 作用于模型和视图。它从存储库(模型)中检索数据,并将其格式化以在视图中显示。
视图 是一个被动界面,它显示数据(模型)并将用户命令(事件)路由到演示者以根据该数据采取行动。
所以 Activity
可以作为一个 overall controller
创建 Presenters
和 Views
并连接它们。
如果我们讨论您的问题,是的,您可以在片段中注册演示者。但是你应该避免在用作视图的片段中创建演示者。
但是在 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
我一直在遵循 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
附加到 Activity
和 Presenters
获取视图 (Fragments
) 作为参数。
在 Fragment
事务提交或 Fragment
(视图)状态恢复后 Presenters
被创建并以 Fragments
(视图)作为参数而不是调用
view.setPresenter(T presenter);
查看方法和Presenters
注册查看。
我认为在 Fragment
中创建 Presenter
不是一个好的做法。首先,它们是 独立的层 。这对于 关注点分离 是非法的。其次,如果您在 Fragment
中创建演示者,则将演示者的生命绑定到视图的 LifeCycle
,当 Fragment
被销毁并重新创建时,您将创建一个新的演示者,但它们是不同的层。
模型 是定义要在用户界面中显示或以其他方式操作的数据的界面。
presenter 作用于模型和视图。它从存储库(模型)中检索数据,并将其格式化以在视图中显示。
视图 是一个被动界面,它显示数据(模型)并将用户命令(事件)路由到演示者以根据该数据采取行动。
所以 Activity
可以作为一个 overall controller
创建 Presenters
和 Views
并连接它们。
如果我们讨论您的问题,是的,您可以在片段中注册演示者。但是你应该避免在用作视图的片段中创建演示者。
但是在 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