前言 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。
- View: 对应于Activity和XML,负责View的绘制以及与用户的交互。
- Model: 依然是实体模型。
- Presenter: 负责完成View与Model间的交互和业务逻辑。
文章图片
但是mvp还是存在着一些缺点:
- MVP是以UI为驱动的模型,更新UI都需要保证能获取到控件的引用,同时更新UI的时候要考虑当前是否是UI线程,也要考虑Activity的生命周期(是否已经销毁等)。
- MVP是以UI和事件为驱动的传统模型,数据都是被动地通过UI控件做展示,但是由于数据的时变性,我们更希望数据能转被动为主动,希望数据能更有活性,由数据来驱动UI。
- V层与P层还是有一定的耦合度。一旦V层某个UI元素更改,那么对应的接口就必须得改,数据如何映射到UI上、事件监听接口这些都需要转变,牵一发而动全身
- 复杂的业务同时也可能会导致P层太大,代码臃肿的问题依然不能解决。
- Presenter层与View层是通过接口进行交互的,接口粒度不好控制。
- View: 对应于Activity和XML,负责View的绘制以及与用户交互。
- Model: 实体模型。
- ViewModel: 负责完成View与Model间的交互,负责业务逻辑。
文章图片
以上各个模式都进行了一遍简单的了解,现在开始介绍封装的MVVM模式的架构,不多说,先上图。
文章图片
这是一个新的MVVM模式的架构图,其实本质还是还是MVVM的思想,只是吧Model的数据来源进行了划分,在repository下面的都是属于model层,只是提供了一个仓库Repository,可以根据需求获取不同的数据。下面开始介绍各个模块:
view层
view层也是上图中的activity或者fragment,继承AppCompatActivity / Fragment,是UI控件的宿主。核心职责是:
- 更新UI控件显示,包括状态及数据,由ViewModel驱动
- 监听UI事件及其生命周期,驱动ViewModel
只做业务逻辑操作,不持有任何UI控件的引用。那数据的更新如何通知到View层,这就要仰仗LiveData,具体使用下面会介绍。
model层
在Repository以下的都属于model层,Model层就是数据层。数据来源有:
- 本地存储数据,如数据库,文件,SharedPreferences(本质也是文件)
- 内存的缓存或临时数据
- 通过各种网络协议获取的远程数据(network)
提供了不使用Databinding的原因:
- 数据绑定增加Bug调试难度。
- 复杂的页面,model也会很大,虽然使用方便了也很容易保证了数据的一致性,当时长期持有,不利于释放内存。
- 数据双向绑定不利于View重用。
MVVM请求框架是基于OKhttp+rxjava2+retrofit2+LiveData实现的结构体系,泛型限定,深度解耦。
viewModel优点:
- 同步关联生命周期
- 数据共享
- 复用性强
- 确保UI界面的数据状态
- 没有内存泄漏,不会因为Activity的不可见导致Crash
- 不用再人为的处理生命周期
- 共享资源
LiveBus.class
public class LiveBus {private static volatile LiveBus instance; private final ConcurrentHashMap
使用方法:
发送数据:
LiveBus.getDefault().postEvent("LiveData","hi LiveData");
接收数据:
LiveBus.getDefault().subscribe("LiveData").observe(this, new Observer
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); }protectedSubscriber 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 BaseViewModelextends 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 AbstractLifecycleActivityextends 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 AbstractLifecycleWithDatabindingActivityextends 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));
protectedT 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 AbstractLifecycleFragmentextends 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 AbstractLifecycleWithDatabindingFragmentextends 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 AbstractLifecycleDialogFragmentextends 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 AbstractLifecycleWithDatabindingDialogFragmentextends 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框架是我查看了众多博文与我自己总结的产物,希望看了博文有兴趣的可以交流交流,毕竟也有理解不到位的地方。而且不同的理解产生了不同的方式。