基于okhttp3+rxjava2+retrofit2的MVVM模式网络请求

前言 MVC、MVP、MVVM是我们工作和面试中都比较重要的一块,但很多时候我们却有点迷惑。有时候看了好多博文都搞不懂他们是啥,有时候想写个MVP模式,写着写着就成了MVC模式。这个请求框架,也是基于我自己的理解和众多网友的博文进行封装的。另外由于本人水平有限,如果写的不对或者不严谨的地方,请不要打我。也希望能多多交流。
概述 说到Android MVVM,相信大家都会想到Databinding框架,然而两者并不能混为一谈,MVVM是一种架构模式,而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个工具。
在封装MVVM网络请求框架之前,我也去看了很多相关的MVVM模式和Databinding使用的博客,所以结合了一下封装了一个MVVM架构模式的网络请求框架。
【基于okhttp3+rxjava2+retrofit2的MVVM模式网络请求】接下来,我们先了解下MVC、MVP、MVVM,在一步步分析MVVM的请求封装。
MVC、MVP、MVVP MVC(VIew-Model-Controller) 早期将 View、Model、Controller 代码块进行划分,使得程序大部分分离,降低耦合。

  • View:XML布局文件。
  • Model:实体模型(数据的获取、存储、数据状态变化)。
  • Controllor:对应于Activity,处理数据、业务和UI。
MVP:(VIew-Model-Presenter) 由于 MVC 中 View和Model之间的依赖太强,导致 Activity 中的代码过于臃肿。为了他们可以绝对独立的存在,慢慢演化出了 MVP。在 MVP 中 View 并不直接使用 Model,它们之间的通信是通过 Presenter (MVC中的Controller) 来进行的。
  • View: 对应于Activity和XML,负责View的绘制以及与用户的交互。
  • Model: 依然是实体模型。
  • Presenter: 负责完成View与Model间的交互和业务逻辑。
基于okhttp3+rxjava2+retrofit2的MVVM模式网络请求
文章图片

但是mvp还是存在着一些缺点:
  • MVP是以UI为驱动的模型,更新UI都需要保证能获取到控件的引用,同时更新UI的时候要考虑当前是否是UI线程,也要考虑Activity的生命周期(是否已经销毁等)。
  • MVP是以UI和事件为驱动的传统模型,数据都是被动地通过UI控件做展示,但是由于数据的时变性,我们更希望数据能转被动为主动,希望数据能更有活性,由数据来驱动UI。
  • V层与P层还是有一定的耦合度。一旦V层某个UI元素更改,那么对应的接口就必须得改,数据如何映射到UI上、事件监听接口这些都需要转变,牵一发而动全身
  • 复杂的业务同时也可能会导致P层太大,代码臃肿的问题依然不能解决。
  • Presenter层与View层是通过接口进行交互的,接口粒度不好控制。
MVVM:(Model–View–ViewModel) MVVM 可以算是 MVP的升级版,将 Presenter 改名为 ViewModel。关键在于 View和Model的双向绑定,当 View 有用户输入后,ViewModel 通知 Model 更新数据,同理 Model 数据更新后,ViewModel 通知 View 更新。
  • View: 对应于Activity和XML,负责View的绘制以及与用户交互。
  • Model: 实体模型。
  • ViewModel: 负责完成View与Model间的交互,负责业务逻辑。
MVVM的目标和思想与MVP类似,利用数据绑定(Data Binding)、依赖属性(Dependency Property)、命令(Command)、路由事件(Routed Event)等新特性,打造了一个更加灵活高效的架构。
基于okhttp3+rxjava2+retrofit2的MVVM模式网络请求
文章图片

以上各个模式都进行了一遍简单的了解,现在开始介绍封装的MVVM模式的架构,不多说,先上图。
基于okhttp3+rxjava2+retrofit2的MVVM模式网络请求
文章图片

这是一个新的MVVM模式的架构图,其实本质还是还是MVVM的思想,只是吧Model的数据来源进行了划分,在repository下面的都是属于model层,只是提供了一个仓库Repository,可以根据需求获取不同的数据。下面开始介绍各个模块:
view层
view层也是上图中的activity或者fragment,继承AppCompatActivity / Fragment,是UI控件的宿主。核心职责是:
  • 更新UI控件显示,包括状态及数据,由ViewModel驱动
  • 监听UI事件及其生命周期,驱动ViewModel
viewModel层
只做业务逻辑操作,不持有任何UI控件的引用。那数据的更新如何通知到View层,这就要仰仗LiveData,具体使用下面会介绍。
model层
在Repository以下的都属于model层,Model层就是数据层。数据来源有:
  • 本地存储数据,如数据库,文件,SharedPreferences(本质也是文件)
  • 内存的缓存或临时数据
  • 通过各种网络协议获取的远程数据(network)
MVVM模式请求框架 本框架有两个使用方法,一种是不是要Databinding,一种是使用Databinding的。前面也说到了,MVVM只是一种架构模式,Databinding是构建MVVM模式的一个工具,但是两种并不冲突。
提供了不使用Databinding的原因:
  • 数据绑定增加Bug调试难度。
  • 复杂的页面,model也会很大,虽然使用方便了也很容易保证了数据的一致性,当时长期持有,不利于释放内存。
  • 数据双向绑定不利于View重用。
提供了两种使用是为了灵活使用,如果想使用Databinding的页面就使用Databinding,不想使用的页面,重用的页面就使用没有Databinding的方式。具体使用看个人需求,毕竟没有最好的框架,只有最合适的框架。
MVVM请求框架是基于OKhttp+rxjava2+retrofit2+LiveData实现的结构体系,泛型限定,深度解耦。
viewModel优点:
  • 同步关联生命周期
  • 数据共享
  • 复用性强
LiveData优点:
  • 确保UI界面的数据状态
  • 没有内存泄漏,不会因为Activity的不可见导致Crash
  • 不用再人为的处理生命周期
  • 共享资源
接下来看看我们使用liveData更新数据的类LiveBus:
LiveBus.class
public class LiveBus {private static volatile LiveBus instance; private final ConcurrentHashMap> mLiveBus; private LiveBus() { mLiveBus = new ConcurrentHashMap<>(); }public static LiveBus getDefault() { if (instance == null) { synchronized (LiveBus.class) { if (instance == null) { instance = new LiveBus(); } } } return instance; }public MutableLiveData subscribe(Object eventKey) { return subscribe(eventKey, ""); }public MutableLiveData subscribe(Object eventKey, String tag) { return (MutableLiveData) subscribe(eventKey, tag, Object.class); }public MutableLiveData subscribe(Object eventKey, Class tClass) { return subscribe(eventKey, null, tClass); }public MutableLiveData subscribe(Object eventKey, String tag, Class tClass) { String key = mergeEventKey(eventKey, tag); if (!mLiveBus.containsKey(key)) { mLiveBus.put(key, new LiveBusData<>(true)); } else { LiveBusData liveBusData = https://www.it610.com/article/mLiveBus.get(key); liveBusData.isFirstSubscribe = false; }return (MutableLiveData) mLiveBus.get(key); }public MutableLiveData postEvent(Object eventKey, T value) { return postEvent(eventKey, null, value); }public MutableLiveData postEvent(Object eventKey, String tag, T value) { MutableLiveData mutableLiveData = https://www.it610.com/article/subscribe(mergeEventKey(eventKey, tag)); mutableLiveData.postValue(value); return mutableLiveData; }public static class LiveBusData extends MutableLiveData {private boolean isFirstSubscribe; LiveBusData(boolean isFirstSubscribe) { this.isFirstSubscribe = isFirstSubscribe; }@Override public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) { super.observe(owner, new ObserverWrapper<>(observer, isFirstSubscribe)); } }private static class ObserverWrapper implements Observer {private Observer observer; private boolean isChanged; private ObserverWrapper(Observer observer, boolean isFirstSubscribe) { this.observer = observer; isChanged = isFirstSubscribe; }@Override public void onChanged(@Nullable T t) { if (isChanged) { if (observer != null) { observer.onChanged(t); } } else { isChanged = true; } }}private String mergeEventKey(Object eventKey, String tag) { String mEventkey; if (!TextUtils.isEmpty(tag)) { mEventkey = eventKey + tag; } else { mEventkey = (String) eventKey; } return mEventkey; }public void clear(Object eventKey) { clear(eventKey, null); }public void clear(Object eventKey, String tag) { if (mLiveBus != null && mLiveBus.size() > 0) { String mEventKey = mergeEventKey(eventKey, tag); mLiveBus.remove(mEventKey); }}}

使用方法:
发送数据:
LiveBus.getDefault().postEvent("LiveData","hi LiveData");

接收数据:
LiveBus.getDefault().subscribe("LiveData").observe(this, new Observer() { public void onChanged(@Nullable Object o) { Log.e("onChanged",((String)o)); } });
LiveBus.getDefault().subscribe(Constants.EVENT_KEY_WORK, LoginBean.class).observe(this, new Observer() { @Override public void onChanged(@Nullable LoginBean loginBean) { LogUtil.e(loginBean.toString()); } });

MVVM架构分层分析 一、Repository基类
public abstract class AbstractRepository { private CompositeDisposable mCompositeDisposable; public MutableLiveData loadState; public AbstractRepository() { loadState = new MutableLiveData<>(); }protected void postState(String state) { if (loadState != null) { loadState.postValue(state); }}protected void addDisposable(Disposable disposable) { mCompositeDisposable = HttpMethods.getCompositeDisposableInstance(); mCompositeDisposable.add(disposable); }protected Subscriber addSubscriber(Flowable flowable, Subscriber subscriber) { return flowable.compose(RxSchedulers.flowableIoMain()).subscribeWith(subscriber); }public void addSubscription(Observable observable, Observer observer) { observable.compose(RxSchedulers.observableIoMain()) .subscribe(observer); }public void unDisposable() { if (mCompositeDisposable != null && mCompositeDisposable.isDisposed()) { mCompositeDisposable.clear(); } }/** * 解除订阅 */ protected void unSubscribe() { if (mCompositeDisposable != null && mCompositeDisposable.isDisposed()) { mCompositeDisposable.clear(); } } }

使用方法:定义一个BaseRepository,继承AbstractRepository
public class BaseRepository extends AbstractRepository { protected ApiServer apiService; public BaseRepository() { if (null == apiService) { apiService = HttpMethods.getInstance().create(ApiServer.class); } }protected void postData(Object eventKey, Object t) { postData(eventKey, null, t); }protected void showPageState(Object eventKey, String state) { postData(eventKey, state); }protected void showPageState(Object eventKey, String tag, String state) { postData(eventKey, tag, state); }protected void postData(Object eventKey, String tag, Object t) { LiveBus.getDefault().postEvent(eventKey, tag, t); } }

二、viewmode基类
public class BaseViewModel extends AndroidViewModel { public T mRepository; public BaseViewModel(@NonNull Application application) { super(application); mRepository = TUtil.getNewInstance(this, 0); }@Override protected void onCleared() { super.onCleared(); if (mRepository != null) { mRepository.unDisposable(); mRepository.unSubscribe(); }} }

使用方法:viewModel类继承BaseViewModel类
public class MainViewModel extends BaseViewModel {public MainViewModel(@NonNull Application application) { super(application); }public void doLogin1(String userName, String pwd) { mRepository.doLogin1(userName,pwd); } public void doLogin2(String userName, String pwd) { mRepository.doLogin2(userName,pwd); } }

三、model类
model类就是实体类,就不介绍了,根据自己需求构建即可。
四、view 从上面的结构图中我们可以知道,view是包含activity和fragment的,而dialog也是包含在fragment中的,所以就区分开了一个一个介绍。
一、activity
1、不使用mvvm模式的activity基类
public abstract class AbstractSimpleActivity extends AppCompatActivity { protected Activity mContext; /** * 绑定布局 * * @return */ protected abstract int getLayoutId(); /** * 初始化事件和数据 */ protected abstract void initEventAndData(); /** * 控件初始化 */ protected abstract void initView(); /** * 修改状态栏颜色 */ protected abstract void transStatusColor(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } setContentView(getLayoutId()); super.onCreate(savedInstanceState); mContext = this; App.getInstance().addActivity(this); initView(); transStatusColor(); initEventAndData(); }@Override protected void onResume() { super.onResume(); }@Override protected void onDestroy() { super.onDestroy(); App.getInstance().removeActivity(this); }/** * 打开一个Activity 默认 不关闭当前activity * * @param className */ public void gotoActivity(Class className) { gotoActivity(className, false, null); }/** * 打开一个Activity,并控制是否finish * * @param classNameclassName * @param isCloseCurrentActivity 是否关闭 */ public void gotoActivity(Class className, boolean isCloseCurrentActivity) { gotoActivity(className, isCloseCurrentActivity, null); }/** * 打开一个activity,并传递数据 * * @param classNameclassName * @param isCloseCurrentActivity 是否关闭 * @param bundlebundle数据 */ public void gotoActivity(Class className, boolean isCloseCurrentActivity, Bundle bundle) { Intent intent = new Intent(this, className); if (bundle != null) { intent.putExtras(bundle); } startActivity(intent); if (isCloseCurrentActivity) { finish(); } }/** * 系统返回键 * * @param item * @return */ @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: //返回 super.onBackPressed(); return true; default: return super.onOptionsItemSelected(item); } } /** * 资源文件绑定 * * @param id资源文件id * @param * @return */ @SuppressWarnings("unchecked") protected T getViewById(int id) { return (T) findViewById(id); } }

2、使用MVVM模式的activity基类
public abstract class AbstractLifecycleActivity extends AppCompatActivity { protected T mViewModel; protected Activity mActivity; /** * 绑定布局 * * @return */ protected abstract int getLayoutId(); /** * 初始化事件和数据 */ protected abstract void initEventAndData(); /** * 控件初始化 */ protected abstract void initView(); /** * 数据绑定 */ protected abstract void dataObserver(); /** * 修改状态栏颜色 */ protected abstract void transStatusColor(); @SuppressLint("RestrictedApi") @Override protected void onCreate(@Nullable Bundle savedInstanceState) { mViewModel = viewModelProviders(this, (Class) TUtil.getInstance(this, 0)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //设置状态栏颜色 //getWindow().setStatusBarColor(0xff24cf5f); } setContentView(getLayoutId()); super.onCreate(savedInstanceState); mActivity = this; //活动控制器 App.getInstance().addActivity(this); initView(); transStatusColor(); initEventAndData(); dataObserver(); }protected T viewModelProviders(AppCompatActivity fragment, @NonNull Class modelClass) { return (T) ViewModelProviders.of(fragment).get(modelClass); }@Override protected void onDestroy() { super.onDestroy(); /** * presenter 解除view订阅 */App.getInstance().removeActivity(this); }@Override protected void onResume() { super.onResume(); }/** * 打开一个Activity 默认 不关闭当前activity * * @param className */ public void gotoActivity(Class className) { gotoActivity(className, false, null); }/** * 打开一个Activity,并控制是否finish * * @param classNameclassName * @param isCloseCurrentActivity 是否关闭 */ public void gotoActivity(Class className, boolean isCloseCurrentActivity) { gotoActivity(className, isCloseCurrentActivity, null); }/** * 打开一个activity,并传递数据 * * @param classNameclassName * @param isCloseCurrentActivity 是否关闭 * @param bundlebundle数据 */ public void gotoActivity(Class className, boolean isCloseCurrentActivity, Bundle bundle) { Intent intent = new Intent(this, className); if (bundle != null) { intent.putExtras(bundle); } startActivity(intent); if (isCloseCurrentActivity) { finish(); } }/** * 系统返回键监听 * * @param item * @return */ @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: super.onBackPressed(); //返回 return true; default: return super.onOptionsItemSelected(item); } }/** * 资源文件绑定 * * @param id资源文件id * @param * @return */ @SuppressWarnings("unchecked") protected T getViewById(int id) { return (T) findViewById(id); } }

3、使用MVVM模式+Databinding模式的activity基类
public abstract class AbstractLifecycleWithDatabindingActivity extends AppCompatActivity { protected T mViewModel; protected D mDatabinding; protected Activity mActivity; /** * 绑定布局 * * @return */ protected abstract int getLayoutId(); /** * 初始化事件和数据 */ protected abstract void initEventAndData(); /** * 控件初始化 */ protected abstract void initView(); /** * 数据绑定 */ protected abstract void dataObserver(); /** * 修改状态栏颜色 */ protected abstract void transStatusColor(); @SuppressLint("RestrictedApi") @Override protected void onCreate(@Nullable Bundle savedInstanceState) { mViewModel = viewModelProviders(this, (Class) TUtil.getInstance(this, 0)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } setContentView(getLayoutId()); super.onCreate(savedInstanceState); mActivity = this; //活动控制器 App.getInstance().addActivity(this); mDatabinding = DataBindingUtil.setContentView(this, getLayoutId()); initView(); transStatusColor(); initEventAndData(); dataObserver(); }protected T viewModelProviders(AppCompatActivity fragment, @NonNull Class modelClass) { return (T) ViewModelProviders.of(fragment).get(modelClass); }@Override protected void onDestroy() { super.onDestroy(); /** * presenter 解除view订阅 */App.getInstance().removeActivity(this); }@Override protected void onResume() { super.onResume(); }/** * 打开一个Activity 默认 不关闭当前activity * * @param className */ public void gotoActivity(Class className) { gotoActivity(className, false, null); }/** * 打开一个Activity,并控制是否finish * * @param classNameclassName * @param isCloseCurrentActivity 是否关闭 */ public void gotoActivity(Class className, boolean isCloseCurrentActivity) { gotoActivity(className, isCloseCurrentActivity, null); }/** * 打开一个activity,并传递数据 * * @param classNameclassName * @param isCloseCurrentActivity 是否关闭 * @param bundlebundle数据 */ public void gotoActivity(Class className, boolean isCloseCurrentActivity, Bundle bundle) { Intent intent = new Intent(this, className); if (bundle != null) { intent.putExtras(bundle); } startActivity(intent); if (isCloseCurrentActivity) { finish(); } }/** * 系统返回键监听 * * @param item * @return */ @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: super.onBackPressed(); //返回 return true; default: return super.onOptionsItemSelected(item); } }/** * 资源文件绑定 * * @param id资源文件id * @param * @return */ @SuppressWarnings("unchecked") protected T getViewById(int id) { return (T) findViewById(id); } }

从上面代码可以看到,关键代码就是
mViewModel = viewModelProviders(this, (Class) TUtil.getInstance(this, 0));

protected T viewModelProviders(AppCompatActivity fragment, @NonNull Class modelClass) { return (T) ViewModelProviders.of(fragment).get(modelClass); }

这里也就是viewmodel的初始化,然后通过viewmodel进行数据的请求,在上面的的viewmodel类中,我们也可以看到,数据的请求其实是交个Repository类去执行的,而viewmodel只是提供一个方法进行调用。
如果使用了Databinding,则多了Databinding与XML布局的绑定
mDatabinding = DataBindingUtil.setContentView(this, getLayoutId());
二、fragment基类 1、不使用MVVM模式的fragment基类
public abstract class AbstractSimpleFragment extends Fragment {protected View mView; protected FragmentActivity mActivity; protected boolean mIsFirstVisible = true; /** * 设置布局文件 * * @return */ protected abstract int getLayoutId(); /** * 数据懒加载 */ protected abstract void lazyLoad(); /** * 当界面不可见时的操作 */ protected abstract void onInVisible(); /** * 控件初始化 */ protected abstract void initView(); @Override public void onAttach(Context context) { mActivity = (FragmentActivity) context; super.onAttach(context); }@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { mView = inflater.inflate(getLayoutId(), container, false); initView(); return mView; }@Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); boolean isVis = isHidden() || getUserVisibleHint(); if (isVis && mIsFirstVisible) { lazyLoad(); mIsFirstVisible = false; } }@Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (!hidden) { onVisible(); } else { onInVisible(); } }@Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser) { onVisible(); } else { onInVisible(); } }/** * 当界面可见时的操作 */ protected void onVisible() { if (mIsFirstVisible && isResumed()) { lazyLoad(); mIsFirstVisible = false; } }@Override public void onDestroyView() { super.onDestroyView(); this.mActivity = null; }@Override public void onDetach() { super.onDetach(); this.mActivity = null; }/** * 资源文件绑定 * * @param id资源文件id * @param * @return */ @SuppressWarnings("unchecked") protected T getViewById(int id) { return (T) mView.findViewById(id); } }

2、使用MVVM模式的fragment基类
public abstract class AbstractLifecycleFragment extends Fragment { protected T mViewModel; protected View mView; protected FragmentActivity mActivity; /** * 设置布局文件 * * @return */ protected abstract int getLayoutId(); /** * 数据懒加载 */ protected abstract void lazyLoad(); /** * 当界面不可见时的操作 */ protected abstract void onInVisible(); /** * 数据绑定 */ protected abstract void dataObserver(); /** * 控件初始化 */ protected abstract void initView(); @Override public void onAttach(Context context) { mActivity = (FragmentActivity) context; super.onAttach(context); }@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { mView = inflater.inflate(getLayoutId(), container, false); mViewModel = viewModelProviders(this, (Class) TUtil.getInstance(this, 0)); if (null != mViewModel) { dataObserver(); } initView(); return mView; }/** * create ViewModelProviders * * @return ViewModel */ protected T viewModelProviders(AbstractLifecycleFragment fragment, @NonNull Class modelClass) { return ViewModelProviders.of(fragment).get(modelClass); }@Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (!hidden) { onVisible(); } else { onInVisible(); } }@Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser) { onVisible(); } else { onInVisible(); } }/** * 当界面可见时的操作 */ protected void onVisible() { if (isResumed()) { lazyLoad(); } }@Override public void onDestroyView() { super.onDestroyView(); this.mActivity = null; }@Override public void onDetach() { super.onDetach(); this.mActivity = null; }/** * 资源文件绑定 * * @param id资源文件id * @param * @return */ @SuppressWarnings("unchecked") protected T getViewById(int id) { return (T) mView.findViewById(id); } }

3、使用MVVM模式+Databinding的fragment基类
public abstract class AbstractLifecycleWithDatabindingFragment extends Fragment { protected T mViewModel; protected D mDataBinding; protected View mView; protected FragmentActivity mActivity; /** * 设置布局文件 * * @return */ protected abstract int getLayoutId(); /** * 数据懒加载 */ protected abstract void lazyLoad(); /** * 当界面不可见时的操作 */ protected abstract void onInVisible(); /** * 数据绑定 */ protected abstract void dataObserver(); /** * 控件初始化 */ protected abstract void initView(); @Override public void onAttach(Context context) { mActivity = (FragmentActivity) context; super.onAttach(context); }@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { mDataBinding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false); mView = mDataBinding.getRoot(); mViewModel = viewModelProviders(this, (Class) TUtil.getInstance(this, 0)); if (null != mViewModel) { dataObserver(); } initView(); return mView; }/** * create ViewModelProviders * * @return ViewModel */ protected T viewModelProviders(AbstractLifecycleWithDatabindingFragment fragment, @NonNull Class modelClass) { return ViewModelProviders.of(fragment).get(modelClass); }@Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (!hidden) { onVisible(); } else { onInVisible(); } }@Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser) { onVisible(); } else { onInVisible(); } }/** * 当界面可见时的操作 */ protected void onVisible() { if ( isResumed()) { lazyLoad(); } }@Override public void onDestroyView() { super.onDestroyView(); this.mActivity = null; }@Override public void onDetach() { super.onDetach(); this.mActivity = null; }/** * 资源文件绑定 * * @param id资源文件id * @param * @return */ @SuppressWarnings("unchecked") protected T getViewById(int id) { return (T) mView.findViewById(id); } }

在fragment的基类中,我们不难发现,viewmodel的初始化跟activity其实是一样的。注意是使用Databinding的方式,在activity中使用Databinding的方式是:
mDatabinding = DataBindingUtil.setContentView(this, getLayoutId());

但是在fragment中就不能使用中种方式了,而是要使用
mDataBinding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false); mView = mDataBinding.getRoot();

如果不会使用Databinding的,可以先去了解了解Databinding如何使用,到时候使用起来就方便多了。
三、dialog基类(不使用MVVM模式的基类就不介绍了) 1、使用MVVM模式的dialog基类
public abstract class AbstractLifecycleDialogFragment extends DialogFragment {@Override public void show(FragmentManager manager, String tag) { try { //防止连续点击add多个fragment manager.beginTransaction().remove(this).commit(); super.show(manager, tag); } catch (Exception e) { e.printStackTrace(); } }protected T mViewModel; protected View mView; protected FragmentActivity mActivity; protected boolean mIsFirstVisible = true; /** * 设置布局文件 * * @return */ protected abstract int getLayoutId(); /** * 数据懒加载 */ protected abstract void lazyLoad(); /** * 当界面不可见时的操作 */ protected abstract void onInVisible(); /** * 数据绑定 */ protected abstract void dataObserver(); /** * 控件初始化 */ protected abstract void initView(); @Override public void onAttach(Context context) { mActivity = (FragmentActivity) context; super.onAttach(context); }@Override public void onStart() { super.onStart(); Window window = getDialog().getWindow(); if (window != null) { WindowManager.LayoutParams layoutParams = window.getAttributes(); layoutParams.dimAmount = 0.0f; window.setAttributes(layoutParams); } }@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { setStyle(R.style.dialog, 0); //设置背景透明 getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); getDialog().setCanceledOnTouchOutside(false); final Window window = getDialog().getWindow(); assert window != null; mView = inflater.inflate(getLayoutId(), ((ViewGroup) window.findViewById(android.R.id.content)), false); mViewModel = viewModelProviders(this, (Class) TUtil.getInstance(this, 0)); if (null != mViewModel) { dataObserver(); } initView(); return mView; }/** * create ViewModelProviders * * @return ViewModel */ protected T viewModelProviders(AbstractLifecycleDialogFragment fragment, @NonNull Class modelClass) { return ViewModelProviders.of(fragment).get(modelClass); }@Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); boolean isVis = isHidden() || getUserVisibleHint(); if (isVis && mIsFirstVisible) { lazyLoad(); mIsFirstVisible = false; } }@Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (!hidden) { onVisible(); } else { onInVisible(); } }@Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser) { onVisible(); } else { onInVisible(); } }/** * 当界面可见时的操作 */ protected void onVisible() { if (mIsFirstVisible && isResumed()) { lazyLoad(); mIsFirstVisible = false; } }@Override public void onDestroyView() { super.onDestroyView(); this.mActivity = null; }@Override public void onDetach() { super.onDetach(); this.mActivity = null; }/** * 资源文件绑定 * * @param id资源文件id * @param * @return */ @SuppressWarnings("unchecked") protected T getViewById(int id) { return (T) mView.findViewById(id); } }

2、使用 MVVM模式+Databinding的dialog基类
public abstract class AbstractLifecycleWithDatabindingDialogFragment extends DialogFragment {@Override public void show(FragmentManager manager, String tag) { try { //防止连续点击add多个fragment manager.beginTransaction().remove(this).commit(); super.show(manager, tag); } catch (Exception e) { e.printStackTrace(); } }protected T mViewModel; protected D mDataBinding; protected View mView; protected FragmentActivity mActivity; protected boolean mIsFirstVisible = true; /** * 设置布局文件 * * @return */ protected abstract int getLayoutId(); /** * 数据懒加载 */ protected abstract void lazyLoad(); /** * 当界面不可见时的操作 */ protected abstract void onInVisible(); /** * 数据绑定 */ protected abstract void dataObserver(); /** * 控件初始化 */ protected abstract void initView(); @Override public void onAttach(Context context) { mActivity = (FragmentActivity) context; super.onAttach(context); }@Override public void onStart() { super.onStart(); Window window = getDialog().getWindow(); if (window != null) { WindowManager.LayoutParams layoutParams = window.getAttributes(); layoutParams.dimAmount = 0.0f; window.setAttributes(layoutParams); } }@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { setStyle(R.style.dialog, 0); //设置背景透明 getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); getDialog().setCanceledOnTouchOutside(false); final Window window = getDialog().getWindow(); assert window != null; mDataBinding = DataBindingUtil.inflate(inflater, getLayoutId(), ((ViewGroup) window.findViewById(android.R.id.content)), false); mView = mDataBinding.getRoot(); //mView = inflater.inflate(getLayoutId(), ((ViewGroup) window.findViewById(android.R.id.content)),false); mViewModel = viewModelProviders(this, (Class) TUtil.getInstance(this, 0)); if (null != mViewModel) { dataObserver(); } initView(); return mView; }/** * create ViewModelProviders * * @return ViewModel */ protected T viewModelProviders(AbstractLifecycleWithDatabindingDialogFragment fragment, @NonNull Class modelClass) { return ViewModelProviders.of(fragment).get(modelClass); }@Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); boolean isVis = isHidden() || getUserVisibleHint(); if (isVis && mIsFirstVisible) { lazyLoad(); mIsFirstVisible = false; } }@Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (!hidden) { onVisible(); } else { onInVisible(); } }@Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser) { onVisible(); } else { onInVisible(); } }/** * 当界面可见时的操作 */ protected void onVisible() { if (mIsFirstVisible && isResumed()) { lazyLoad(); mIsFirstVisible = false; } }@Override public void onDestroyView() { super.onDestroyView(); this.mActivity = null; }@Override public void onDetach() { super.onDetach(); this.mActivity = null; }/** * 资源文件绑定 * * @param id资源文件id * @param * @return */ @SuppressWarnings("unchecked") protected T getViewById(int id) { return (T) mView.findViewById(id); } }

MVVM模式的各个模块都接收完了,接下来就是获取数据的模块了,上面也介绍了,数据的获取是在Repository类中进行的,继续Look。
既然是一个网络请求框架,那肯定是少不了网络请求的模块的。
网络请求初始化
HttpMethods .getInstanceBuilder() .setBaseUrl(Constants.getBaseUrl(Constants.SERVER_TYPE))//设置域名 .setLogLevel(LogLevel.ERROR)//设置日志打印级别,使用默认的日志打印才需要设置这个 .setLogName("MVVMFenfNiaoNewRetail")//设置默认日志打印名字 .setIsOpenLog(true)//设置是否开启框架默认的日志打印 //.setCookieJar(new CookieJarImpl())//设置自定义的cookiejar //.setLogger(new HttpLogger())//设置自定义logger,此设置是打印网络请求的数据(如果设置了自定义的,则框架默认的则不需要设置) //.setLevel(LoggerLevel.BODY)//设置日志打印级别(自定义logger可设置,框架默认的是BODY级别,如果上架需要关闭日志打印,则设置setIsOpenLog(false)即可) .setReadTimeOut(60) .setConnectTimeOut(60) .setWriteTimeOut(60) //.setInterceptor(new CommonParametersInterceptor())//设置拦截器 //.setNetworkInterceptor(new CommonParametersInterceptor())//设置拦截器 //.setFactory(CustomConverterFactory.create())//设置自定义解析器 .setInterceptors(new CommonParametersInterceptor()); //设置多个拦截器

初始化就不多说了,这个请求跟我的另外一篇博文的请求初始化是一样的,如果不懂可以查看我另外一篇博文。
网络请求框架(基于okhttp+rxjava2+retrofit2的mvp模式网络请求框架+RxBus+RxView控制按钮重复点击)
源代码github地址
网络请求方式 介绍网络请求前先贴出Repository的代码
public class MainRepository extends BaseRepository { public void doLogin1(String userName, String pwd) { Flowable flowable = apiService.login2(userName, pwd).map(new HttpResultFunc()); addDisposable((Disposable) addSubscriber(flowable, new DisposableSubscriberCallBack(new ApiCallback() { @Override public void onSuccess(LoginBean model) { LogUtil.e(model.toString()); postData(Constants.EVENT_KEY_WORK, model); }@Override public void onFailure(String msg) { ToastUtil.shortShow(msg); } }))); }public void doLogin2(String userName, String pwd) { Observable observable = apiService.login5(userName, pwd).map(new HttpResultFunc()); addSubscription(observable, new SubscriberCallBack(new ApiCallback() { @Override public void onSuccess(LoginBean model) { LogUtil.e(model.toString()); postData(Constants.EVENT_KEY_WORK1, model); }@Override public void onFailure(String msg) { ToastUtil.shortShow(msg); } })); } }

从上面的代码可以看到,网络请求有两种方式,Observable方式和Flowable方式,对应的APIservice接口如下:
@POST("/login") Flowable> login2(@Query("userName") String userName, @Query("pwd") String pwd); @POST("/login") Observable> login5(@Query("userName") String userName, @Query("pwd") String pwd);


具体使用哪一种方式看个人爱好和需求。
既然我们获取到了数据了,就又回到了我们一开始就说到了数据更新LiveBus,在获取数据成功的时候,使用postData(Constants.EVENT_KEY_WORK1, model); 把对应的数据方式出去,只有注册了相关的监听才能进行数据的接收,下面看一下接收的代码:
LiveBus.getDefault().subscribe(Constants.EVENT_KEY_WORK1, LoginBean.class).observe(this, new Observer() { @Override public void onChanged(@Nullable LoginBean loginBean) { LogUtil.e(loginBean.toString()); mDatabinding.setViewModel(loginBean); } }); LiveBus.getDefault().subscribe(Constants.EVENT_KEY_WORK, LoginBean.class).observe(this, new Observer() { @Override public void onChanged(@Nullable LoginBean loginBean) { LogUtil.e(loginBean.toString()); mDatabinding.setViewModel(loginBean); } });

这里只提供了网络层的数据,在实际应用中可拆分类loacl data和remote data,可根据项目需求自行处理。
最后,整个MVVM框架都离不开lifecycle,下面贴一下lifecycle的依赖方式
在app的build.gradle中导入
implementation "android.arch.lifecycle:runtime:$archVersion" implementation "android.arch.lifecycle:extensions:$archVersion" annotationProcessor "android.arch.lifecycle:compiler:$archVersion"

archVersion是在根目录下的,也可以直接写入版本号。
ext{ archVersion='1.1.1' }

MVVM网络请求框架使用 在根目录下的build.gradle中添加以下代码
allprojects { repositories { ... maven { url 'https://jitpack.io' } } }

在app下的build.gradle中添加
dependencies { implementation 'com.github.freakcsh:MVVMHttpManager:1.0.0' }

代码传送门 总结 可能看了这个框架的人会觉得,使用这个框架,代码量并没有减少多少,可能还会变多了,相对于MVP模式,可能代码量是没有减少多少,但是在解耦方面来说,是比MVP模式解耦了,MVVM模式的viewmodel没有持有view的对象,也不需要考虑因为View不存在导致的crash。
在前面我也说了,没有最好的框架,只有最适合的框架。而且MVVM只是一个架构模式,实现看自己需求而定。
此MVVM框架是我查看了众多博文与我自己总结的产物,希望看了博文有兴趣的可以交流交流,毕竟也有理解不到位的地方。而且不同的理解产生了不同的方式。

    推荐阅读