资讯专栏INFORMATION COLUMN

Fragment切换时,MVP中的P不能被重新创建

Reducto / 3492人阅读

摘要:把项目的登陆注册和修改密码全部替换成顺便通过简单的模式来实现简单记录下遇到的一些问题谁是这里把做为而不是宿主具体原因有待深究然而能力有限的管理登陆注册和修改密码一个三个继承自基类的并各自对应自己的和这里使用到了使用来管理的生命周期并在中初始

把项目的登陆,注册和修改密码全部替换成Fragment,顺便通过简单的MVP模式来实现,简单记录下遇到的一些问题.

谁是V

这里把Fragment做为V,而不是宿主Activity.(具体原因有待深究,然而能力有限)

Fragment的管理

登陆,注册和修改密码,一个三个Fragment,继承自基类的IBaseFragment,并各自对应自己的P和M.

public abstract class IBaseFragment extends Fragment implements IBaseView

这里使用到了DataBinding.

使用Loader来管理P的生命周期,并在IBaseFragment中初始化

PresenterLoader代码如下:

    public class PresenterLoader

extends Loader { private P prensenter; private PresenterFactory

factory; /** * Stores away the application context associated with context. * Since Loaders can be used across multiple activities it"s dangerous to * store the context directly; always use {@link #getContext()} to retrieve * the Loader"s Context, don"t use the constructor argument directly. * The Context returned by {@link #getContext} is safe to use across * Activity instances. * * @param context used to retrieve the application context. */ public PresenterLoader(Context context, PresenterFactory

factory) { super(context); this.factory = factory; } @Override protected void onStartLoading() { super.onStartLoading(); if (prensenter!=null){ deliverResult(prensenter); return; } forceLoad(); } @Override protected void onForceLoad() { super.onForceLoad(); prensenter = factory.create(); deliverResult(prensenter); } @Override protected void onStopLoading() { super.onStopLoading(); } @Override protected void onReset() { super.onReset(); if (prensenter!=null) { prensenter.detach(); prensenter = null; } } }

 @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        LoaderManager loaderManager = activity.getSupportLoaderManager();
        loaderManager.initLoader(LOADER_ID, null, new LoaderManager.LoaderCallbacks

() { @Override public Loader

onCreateLoader(int id, Bundle args) { return new PresenterLoader

(activity, new PresenterFactory

() { @Override public P create() { return createPresenter(); } }); } @Override public void onLoadFinished(Loader

loader, P presenter) { IBaseFragment.this.presenter = presenter; } @Override public void onLoaderReset(Loader

loader) { } }); }

public class PresenterLoader

extends Loader

接口PresenterFactory用于生成对应的P

抽象方法createPresenter();由子类负责具体实现

public interface PresenterFactory

{ P create(); }

fragment的切换流程:

登陆--->注册---->登陆

登陆--->修改密码---->登陆

从登陆界面跳转到注册/修改密码使用如下方法:

getSupportFragmentManager().beginTransitation().add(containerId,fragment,tag).addBackToStack(tag).commit();

通过addBackToStack将当前添加的Fragment添加到回退栈

另外这里采用了add(containerId,fragment,tag)而不是replace是为了点击实体返回键时,能回到登陆界面

这里有个坑

在fragment之间切换时,遇到一个坑.举例:从登陆跳转到注册页面,这个时候,注册页面的p的类型仍是登陆页面的p类型.起初我以为是IBaseFragment在OnActivityCreated()初始化LoadManager只进行了一次.然而打断点发现,每次fragment切换这个方法都会执行到.这时才明白是loaderManager.initLoader(LOADER_ID, null, new LoaderManager.LoaderCallbacks)这里的LOADER_ID参数的问题.在IBaseFragment中,这个参数只赋值一次,那么生成的Loader对象也只有一个,导致从登陆页面切换到别的页面时,P不再被重新创建,仍然是登陆界面那个P.

解决办法: 在IBaseFragment中定义一个LOADER_ID如下:

 protected   int LOADER_ID = 210;

这里用protected修饰,保证可以被子类修改
然后在注册和修改页面重新赋值这个变量
如:

    RegisteFragment.java
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        LOADER_ID = 211;
    }

这样就解决了P的问题.

Fragment的返回

监听屏幕返回按钮事件

public boolean onKeyDown(int keyCode, KeyEvent event)

如何弹出回退栈中的Fragment(我们已经在前面通过add和addBackToStack方法将fragment加入到回退栈)
FragmentManager有如下API:

1. popBackStackImmediate();//立即弹出
2. popBackStack(String tag,int flag);//这里的tag是add方法中最后一个参数tag,flag可以是0和                 FragmentManager.POP_BACK_STACK_INCLUSIVE,0表示不弹出自身,后者表示连同自身弹出.

通过FragmentManager.getBackStackEntryCount()得到回退栈中添加的个数,然后不断弹出,直到剩下一个为止.

   @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode==KeyEvent.KEYCODE_BACK&&event.getAction()==KeyEvent.ACTION_DOWN){
            FragmentManager fragmentManager = getSupportFragmentManager();
            if (fragmentManager.getBackStackEntryCount()>1) {
                while (fragmentManager.getBackStackEntryCount() > 1) {
                    fragmentManager.popBackStackImmediate();
                }
            }else
                finish();
        }
        return true;//这里要返回true,不然回退到最后一个可能会出现空白页面
    }

大致就这样,简单总结下.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67440.html

相关文章

  • 改造 Android 官方架构组件 ViewModel

    摘要:前言官方架构组件在今年月份大会上被公布直到月份一直都是测试版由于工作比较繁忙期间我只是看过类似的文章但没有在实际项目中使用过更没有看过源码所以对这几个组件的使用很是生疏同时也觉得这几个组件非常高大上非常神秘直到月份官方架构组件正式版发布并且 前言 Android 官方架构组件在今年 5 月份 Google I/O 大会上被公布, 直到 11 月份一直都是测试版, 由于工作比较繁忙, 期...

    DevTTL 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<