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

前言

MVC、MVP、MVVM是我们工作和面试中都比较重要的一块,但很多时候我们却有点迷惑。有时候看了好多博文都搞不懂他们是啥,有时候想写个MVP模式,写着写着就成了MVC模式。这个请求框架,也是基于我自己的理解和众多网友的博文进行封装的。另外由于本人水平有限,如果写的不对或者不严谨的地方,请不要打我。也希望能多多交流。

概述

说到Android MVVM,相信大家都会想到Databinding框架,然而两者并不能混为一谈,MVVM是一种架构模式,而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个工具。

在封装MVVM网络请求框架之前,我也去看了很多相关的MVVM模式和Databinding使用的博客,所以结合了一下封装了一个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间的交互和业务逻辑。

但是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)等新特性,打造了一个更加灵活高效的架构。

以上各个模式都进行了一遍简单的了解,现在开始介绍封装的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<Object, LiveBusData<Object>> 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 <T> MutableLiveData<T> subscribe(Object eventKey) {
        return subscribe(eventKey, "");
    }

    public <T> MutableLiveData<T> subscribe(Object eventKey, String tag) {
        return (MutableLiveData<T>) subscribe(eventKey, tag, Object.class);
    }

    public <T> MutableLiveData<T> subscribe(Object eventKey, Class<T> tClass) {
        return subscribe(eventKey, null, tClass);
    }

    public <T> MutableLiveData<T> subscribe(Object eventKey, String tag, Class<T> tClass) {
        String key = mergeEventKey(eventKey, tag);
        if (!mLiveBus.containsKey(key)) {
            mLiveBus.put(key, new LiveBusData<>(true));
        } else {
            LiveBusData liveBusData = mLiveBus.get(key);
            liveBusData.isFirstSubscribe = false;
        }

        return (MutableLiveData<T>) mLiveBus.get(key);
    }

    public <T> MutableLiveData<T> postEvent(Object eventKey, T value) {
        return postEvent(eventKey, null, value);
    }

    public <T> MutableLiveData<T> postEvent(Object eventKey, String tag, T value) {
        MutableLiveData<T> mutableLiveData = subscribe(mergeEventKey(eventKey, tag));
        mutableLiveData.postValue(value);
        return mutableLiveData;
    }


    public static class LiveBusData<T> extends MutableLiveData<T> {

        private boolean isFirstSubscribe;

        LiveBusData(boolean isFirstSubscribe) {
            this.isFirstSubscribe = isFirstSubscribe;
        }

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
            super.observe(owner, new ObserverWrapper<>(observer, isFirstSubscribe));
        }
    }

    private static class ObserverWrapper<T> implements Observer<T> {

        private Observer<T> observer;

        private boolean isChanged;

        private ObserverWrapper(Observer<T> 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<Object>() {
  public void onChanged(@Nullable Object o) {
  Log.e("onChanged",((String)o));
 }
 });
LiveBus.getDefault().subscribe(Constants.EVENT_KEY_WORK, LoginBean.class).observe(this, new Observer<LoginBean>() {
    @Override
    public void onChanged(@Nullable LoginBean loginBean) {
        LogUtil.e(loginBean.toString());
 
    }
});

MVVM架构分层分析

一、Repository基类

public abstract class AbstractRepository {
    private CompositeDisposable mCompositeDisposable;

    public MutableLiveData<String> 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 <T> Subscriber<T> addSubscriber(Flowable<T> flowable, Subscriber<T> subscriber) {
        return flowable.compose(RxSchedulers.<T>flowableIoMain()).subscribeWith(subscriber);
    }

    public <T> void addSubscription(Observable<T> observable, Observer<T> observer) {
        observable.compose(RxSchedulers.<T>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<T extends AbstractRepository> 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<MainRepository> {

    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 className              className
     * @param isCloseCurrentActivity 是否关闭
     */
    public void gotoActivity(Class<?> className, boolean isCloseCurrentActivity) {
        gotoActivity(className, isCloseCurrentActivity, null);
    }

    /**
     * 打开一个activity,并传递数据
     *
     * @param className              className
     * @param isCloseCurrentActivity 是否关闭
     * @param bundle                 bundle数据
     */
    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 <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    protected <T extends View> T getViewById(int id) {
        return (T) findViewById(id);
    }
}

2、使用MVVM模式的activity基类

public abstract class AbstractLifecycleActivity<T extends BaseViewModel> 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<T>) 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 extends ViewModel> 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 className              className
     * @param isCloseCurrentActivity 是否关闭
     */
    public void gotoActivity(Class<?> className, boolean isCloseCurrentActivity) {
        gotoActivity(className, isCloseCurrentActivity, null);
    }

    /**
     * 打开一个activity,并传递数据
     *
     * @param className              className
     * @param isCloseCurrentActivity 是否关闭
     * @param bundle                 bundle数据
     */
    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 <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    protected <T extends View> T getViewById(int id) {
        return (T) findViewById(id);
    }
}

3、使用MVVM模式+Databinding模式的activity基类

public abstract class AbstractLifecycleWithDatabindingActivity<T extends BaseViewModel, D extends ViewDataBinding> 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<T>) 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 extends ViewModel> 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 className              className
     * @param isCloseCurrentActivity 是否关闭
     */
    public void gotoActivity(Class<?> className, boolean isCloseCurrentActivity) {
        gotoActivity(className, isCloseCurrentActivity, null);
    }

    /**
     * 打开一个activity,并传递数据
     *
     * @param className              className
     * @param isCloseCurrentActivity 是否关闭
     * @param bundle                 bundle数据
     */
    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 <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    protected <T extends View> T getViewById(int id) {
        return (T) findViewById(id);
    }
}

从上面代码可以看到,关键代码就是

mViewModel = viewModelProviders(this, (Class<T>) TUtil.getInstance(this, 0));
protected <T extends ViewModel> 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 <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    protected <T extends View> T getViewById(int id) {
        return (T) mView.findViewById(id);
    }
}

2、使用MVVM模式的fragment基类

public abstract class AbstractLifecycleFragment<T extends BaseViewModel> 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<T>) TUtil.getInstance(this, 0));
        if (null != mViewModel) {
            dataObserver();
        }
        initView();
        return mView;
    }

    /**
     * create ViewModelProviders
     *
     * @return ViewModel
     */
    protected <T extends ViewModel> T viewModelProviders(AbstractLifecycleFragment fragment, @NonNull Class<T> 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 <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    protected <T extends View> T getViewById(int id) {
        return (T) mView.findViewById(id);
    }
}

3、使用MVVM模式+Databinding的fragment基类

public abstract class AbstractLifecycleWithDatabindingFragment<T extends BaseViewModel, D extends ViewDataBinding> 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<T>) TUtil.getInstance(this, 0));
        if (null != mViewModel) {
            dataObserver();
        }
        initView();
        return mView;
    }

    /**
     * create ViewModelProviders
     *
     * @return ViewModel
     */
    protected <T extends ViewModel> T viewModelProviders(AbstractLifecycleWithDatabindingFragment fragment, @NonNull Class<T> 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 <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    protected <T extends View> 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<T extends BaseViewModel> 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<T>) TUtil.getInstance(this, 0));
        if (null != mViewModel) {
            dataObserver();
        }
        initView();
        return mView;
    }

    /**
     * create ViewModelProviders
     *
     * @return ViewModel
     */
    protected <T extends ViewModel> T viewModelProviders(AbstractLifecycleDialogFragment fragment, @NonNull Class<T> 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 <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    protected <T extends View> T getViewById(int id) {
        return (T) mView.findViewById(id);
    }
}

2、使用 MVVM模式+Databinding的dialog基类

public abstract class AbstractLifecycleWithDatabindingDialogFragment<T extends BaseViewModel, D extends ViewDataBinding> 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<T>) TUtil.getInstance(this, 0));
        if (null != mViewModel) {
            dataObserver();
        }
        initView();
        return mView;
    }

    /**
     * create ViewModelProviders
     *
     * @return ViewModel
     */
    protected <T extends ViewModel> T viewModelProviders(AbstractLifecycleWithDatabindingDialogFragment fragment, @NonNull Class<T> 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 <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    protected <T extends View> 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<LoginBean>());
        addDisposable((Disposable) addSubscriber(flowable, new DisposableSubscriberCallBack<LoginBean>(new ApiCallback<LoginBean>() {
            @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<LoginBean> observable = apiService.login5(userName, pwd).map(new HttpResultFunc<LoginBean>());
        addSubscription(observable, new SubscriberCallBack<LoginBean>(new ApiCallback<LoginBean>() {
            @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<HttpResult<LoginBean>> login2(@Query("userName") String userName,
                                       @Query("pwd") String pwd);

@POST("/login")
Observable<HttpResult<LoginBean>> 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<LoginBean>() {
    @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<LoginBean>() {
    @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框架是我查看了众多博文与我自己总结的产物,希望看了博文有兴趣的可以交流交流,毕竟也有理解不到位的地方。而且不同的理解产生了不同的方式。

 

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OkHttp 是一个用于进行网络请求的开源框架,它基于 Java 的 HttpURLConnection 类进行封装,提供了更简单、更强大的网络请求功能。 Retrofit2 是一个基于 OkHttp网络请求框架,它通过注解和反射的方式,将网络请求接口转换成具体的网络请求动作。同时,Retrofit2 也提供了许多强大的功能,例如请求头、请求体的自定义、请求解析器的设置、请求拦截器等。 RxJava2 是一个响应式编程框架,它提供了一种更优雅和简洁的处理异步操作的方式。通过使用观察者模式和链式调用的方式,我们可以简化对多个异步操作的管理和处理,同时提供了丰富的操作符,用于处理和组合异步数据流。 MVVM 是一种用于设计和实现用户界面的架构模式。它将应用程序的界面逻辑和数据逻辑分开,并通过数据绑定机制实现二者之间的通信。在 MVVM 中,Model 层负责数据的获取和处理,View 层负责界面的显示和用户输入的处理,而 ViewModel 则负责衔接二者之间的通信。 通过将 OkHttpRetrofit2、RxJava2 和 MVVM 结合使用,我们可以构建出一个功能强大、性能优秀、响应迅速的网络请求和数据处理框架。OkHttp 提供了稳定可靠的网络请求功能,Retrofit2 则提供了简单易用的网络接口转换方式,RxJava2 则提供了异步数据处理和链式调用的能力,而 MVVM 则提供了一种清晰的架构模式,使得我们可以更好地组织应用程序的逻辑。总的来说,这些技术和框架的结合能够让我们在开发中更加高效、稳定和灵活。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值