MVVM模式基类抽取Fragment的一些小实践经验

MVVM模式基类抽取Fragment的一些小实践经验


很多情况下不使用Activity,而是使用fragment,那么从开发角度出发,抽取基类就显得再普通不过了,下面简单记录一下实践的经验吧。

前提

首先得了解一下androdid应用打开后加载数据带显示的这样一个流程,这个步骤大致可以分为以下:

  1. 打开应用
  2. 访问权限
  3. 进入主页面
    3.1 显示无需加载数据的那一部分UI
    3.2 显示需要加载数据部分的缺省图
    3.3 等待数据加载后显示并隐藏缺省图
  4. 某些操作唤起弹窗
  5. … …
    暂时列举这些

提取共性

从上述可以看到有些是所有的页面都具有的,这就是共性,比如网络情况,加载缺省图,弹窗,主题变更这些

BaseFragment

BaseFragment一般继承Fragment,那么回忆一下Fragment的生命周期
在这里插入图片描述
那么思考一下,比如说每一个Fragment都需要绑定Activity,那么onAttach方法就属于共性,这个主要就是拿到context,再比如说每一个Fragment都需要监听网络对吧,我们可以在BaseFragment或者Activity注册网络的监听,接收后调用方法,方法空实现,让子类重写做自己的处理,还有可以封装一些弹窗的方法等,大致如下:

public class BaseFragment extends Fragment {

    private BroadcastReceiver mNetworkReceiver;
    private Context mContext;


    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        mContext = context;
    }
    
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //这里主要完成一些与UI无关的操作,初始化Fragment,当然,一般也不在这里初始化数据
    }

    public void registerNetworkChanged() {
        mNetworkReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                //从这里解析结果,调onNetworkChanged()传递结果出去
            }
        };
        IntentFilter filter = new IntentFilter();
        filter.addAction("这里写网络的这个广播类型");
        mContext.registerReceiver(mNetworkReceiver,filter);
    }

    protected void onNetworkChanged(boolean connect){

    }

    protected void unRegisterNetworkChange() {
        try {
            if (null != mNetworkReceiver) {
                mContext.unregisterReceiver(mNetworkReceiver);
                mNetworkReceiver = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void showToastByStr(String msg){
        //弹出弹窗的具体实现
    }

    public void showToastByRsd(int rsd){
        //弹出弹窗的具体实现
    }
}

到这就很奇怪,那还有其他生命周期呢,加载view呢
这个一般不再最顶层的BaseFragment写,因为有时候模块不同,使用的结构也不同,需要各自去实现,可以理解为可以在下面一种结构再进行一次抽取:这里使用MVVM结构来举例。

MVVMBaseFragment

由于MVVM的核心是完全解耦数据层与UI层,这就需要先具备一些mvvm的相关知识,比如说这行代码:

public class MVVMBaseFragment<VM extends ViewModel> extends BaseFragment {
}

这里简单理解就是子类在继承MVVMBaseFragment时需要指定一个泛型,且是需要继承ViewModel的,这样就可以在MVVMBaseFragment拿到这个泛型VM并且将其变成ViewModel,这样就不用再每个Fragment中自己去创建ViewModel了。

ok继续,接下来就是onCreateView了,这个方法在Fragment中是用来创建Fragment的,再通俗一点加载UI的

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

这就很简单了,加载xml文件的肯定是可以抽出来的,加载之后需要初始化View,这个肯定也是可以抽出来的于是:

public abstract class MVVMBaseFragment<VM extends ViewModel> extends BaseFragment {

    private View mRootView;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mRootView = inflater.inflate(setContentView(), container, false);
        initView(mRootView);
        return mRootView;
    }

    protected abstract void initView(View view);

    protected abstract int setContentView();

}

那么下面就需要明确一个小点,ViewModel什么时候创建,这里思考到在initView之后就需要初始化数据了,所以ViewModel的建立应该在initView之前
于是:

public abstract class MVVMBaseFragment<VM extends ViewModel> extends BaseFragment {

    private View mRootView;
    private VM mViewModel;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mRootView = inflater.inflate(setContentView(), container, false);
        CreateViewModel();
        initView(mRootView);
        return mRootView;
    }

    private void CreateViewModel() {
        if (mViewModel == null) {
            Class<VM> vmClass = null;
            Type type = getClass().getGenericSuperclass();
            if (type instanceof ParameterizedType) {
                vmClass = (Class<VM>) ((ParameterizedType) type).getActualTypeArguments()[0];
            } else {
                //使用BaseViewModel
            }
            mViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(vmClass);
            getLifecycle().addObserver(mViewModel);
        }
    }

    protected abstract void initView(View view);

    protected abstract int setContentView();

}

上面有一句

getLifecycle().addObserver(mViewModel);

这个后面具体解释一下,另写一遍再附链接,很好用的无感化避免OOM

接着上面的,现在已经走完onCreateView了,接着的几个方法一般不会在基类中实现,有需要的子类可以重写自己处理,但是onDestroy这个方法还是需要的,可以直接在基类中释放掉viewmodel这种的资源。

还有,之前在最BaseFragment中添加了弹窗方法,于是还应该想到每一个Fragment加载数据时应该有结果的对吧。于是添加上:

    protected void onLoadRetry() {

    }

    protected void showLoading() {

    }

    protected void showLoadSuccess() {

    }


    protected void showLoadFailed() {

    }


    protected void showEmpty() {

    }
    
    protected void showSearchEmpty() {
    }

好了,到这里我们的基类Fragment大致就已经完成了,接着写基类ViewModel

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值