Hement:MVP架构中的网络框架(RxJava2+Retrofit2+RxAndroid)

  • 如何设计好网络框架,我心中也没答案,看过很多别人的轮子,有些太简单,有限过于复杂,有些为了满足去请求网络,褒贬不一
  • 本文的网络框架基于我三年前的网络框架的升级版,具体请看这里 MVP网络框架(Retorfit+Rxjava+Rxandroid)

加入依赖

1
2
3
4
5
6
api "com.squareup.retrofit2:retrofit:2.5.0"
api "com.squareup.retrofit2:converter-gson:2.5.0"
api "com.squareup.retrofit2:adapter-rxjava2:2.5.0"
api 'io.reactivex.rxjava2:rxandroid:2.1.0'
api 'io.reactivex.rxjava2:rxjava:2.2.2'
api "com.squareup.okhttp3:logging-interceptor:3.12.0"
  • rxjava:是反应式扩展的Java VM实现:一个用于使用可观察序列组成异步和基于事件的程序的库。
  • rxandroid:这个模块向RxJava添加了最少的类,使得在Android应用程序中编写反应性组件变得简单且无麻烦。更具体地说,它提供了在主线程或在任何Looper上调度的调度器。
  • converter-gson:通过GsonConverterFactoryRetrofit添加Gson支持
  • logging-interceptor:可以很直观的观察到网络请求的日记
    ![image.png](https://upload-images.jianshu.io/upload_images/5363507-46540b7a41e10c5a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    image.png
  • adapter-rxjava2:一个用于适应RXJava 2类型的适配器。

搭建网络框架

  • IMvpView
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public interface IMvpView {

    /**
    * 数据失败的同一处理
    * @param errorCode
    * @param errorMsg
    */
    void getDataFail(String errorCode, String errorMsg);

    /**
    * 发成异常的同一处理
    * @param e
    */
    void onError(Throwable e);
    }
  • IPresenter 处理和View的生命周期

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    public interface IPresenter<V extends IMvpView> {

    /**
    * 和view结合
    * @param mvpView
    */
    void attachView(V mvpView);

    /**
    * 和view 断开
    */
    void detachView();
    }
  • BasePresenter 所有Presenter的基类,同时绑定所有Activity的生命周期

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    public class BasePresenter<V extends IMvpView> implements IPresenter<V> {


    private V mMvpView;

    @Override
    public void attachView(V mvpView) {
    mMvpView = mvpView;
    }

    @Override
    public void detachView() {
    mMvpView = null;
    }

    /**
    * 判断是否还在连接在一起的
    * @return
    */
    public boolean isViewAttached() {
    return mMvpView != null;
    }

    public V getMvpView() {
    return mMvpView;
    }

    /**
    * 检查View是否附着
    */
    public void checkViewAttached() {
    if (!isViewAttached()) throw new MvpViewNotAttachedException();
    }

    public static class MvpViewNotAttachedException extends RuntimeException {
    public MvpViewNotAttachedException() {
    super("在绑定数据之前一定要绑定视图");
    }
    }

    /**
    * 这是Observer 中的 onServer ,当我们调用这个方法,直接就不会走到 onNext中去
    * @param disposable
    */
    public void dispose(Disposable disposable) {
    if (disposable != null && !disposable.isDisposed()) {
    disposable.dispose();
    }
    }
    }
  • 总体结构图
    总体结构图

    网络框架DataManager

  • 根据上篇文章的设计思路 Hement:MVP架构设计(一)
    Android中的MVP模式.jpg
  • 可以知道DataManager不仅仅是处理网络请求那么简单,同时还需要处理本地存储SharedPreferencesSQLite
  • 所以就转变成了,DataManager向外界提供数据对象,数据的处理已经帮您处理好了,使用的时候只需要获取你想要的对象实例,就可以了,具体封装如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    @Singleton
    public class DataManager {


    private final IRemoteServer mIRemoteServer;
    private final PreferencesHelper mPreferencesHelper;
    private final DatabaseHelper mDatabaseHelper;

    @Inject
    public DataManager(IRemoteServer server, PreferencesHelper preferencesHelper, DatabaseHelper databaseHelper) {
    mIRemoteServer = server;
    mPreferencesHelper = preferencesHelper;
    mDatabaseHelper = databaseHelper;
    }

    public void loadData(String key, String day, BaseObserver observer) {
    Observable<SMResponse<ArrayList<TodayBean>>> today = mIRemoteServer.getToday(key, day);
    today.observeOn(AndroidSchedulers.mainThread())
    .subscribeOn(Schedulers.io())
    .subscribe(observer);
    }

    public PreferencesHelper getPreferencesHelper() {
    return mPreferencesHelper;
    }

    /**
    * 从网络获取数据,缓存到数据库,然后从数据库中取数据
    * @return
    */
    public Observable<TodayBean> syncDBBean() {
    return mIRemoteServer.getToday("b15674dbd34ec00ded57b369dfdabd90", "1/1").concatMap(new Function<SMResponse<ArrayList<TodayBean>>, ObservableSource<? extends TodayBean>>() {
    @Override
    public ObservableSource<? extends TodayBean> apply(@NonNull SMResponse<ArrayList<TodayBean>> response)
    throws Exception {
    return mDatabaseHelper.setDBData(response.result);
    }
    });
    }

    /**
    * 从数据库中取数据
    * @return
    */
    public Observable<List<TodayBean>> getDBBean() {
    return mDatabaseHelper.getDBData().distinct();
    }
    }

网络框架如何使用

  • 这里使用的是聚合数据的接口 ,在这里感谢无私的贡献,三年了这个接口还能用,万分感谢

    1
    http://v.juhe.cn/todayOnhistory/queryEvent.php?key=b15674dbd34ec00ded57b369dfdabd90&date=1/1
  • 1、定义远程Server:IRemoteServer,在这里我把以前的单独生成的RetrofitServer抽取到IRemoteServer,因为项目使用了Dagger2,后面介绍

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public interface IRemoteServer {
    /**
    * http://v.juhe.cn/todayOnhistory/queryEvent.php?key=b15674dbd34ec00ded57b369dfdabd90&date=1/1
    * @param key 申请的key
    * @param date 日期
    * @return 返回历史上的今天
    */
    @GET("queryEvent.php")
    Observable<SMResponse<ArrayList<TodayBean>>> getToday(@Query("key") String key, @Query("date") String date);

    class Creator {
    public static IRemoteServer newHementService() {
    return SMRetrofit.getService(HementApplication.getContext(), IRemoteServer.class);
    }
    }
    }
  • 2、DataManager中的线程调度,结果回调到AndroidSchedulers.mainThread()线程,就是安卓的UI线程。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    private final IRemoteServer mIRemoteServer;
    private final PreferencesHelper mPreferencesHelper;
    private final DatabaseHelper mDatabaseHelper;

    @Inject
    public DataManager(IRemoteServer server, PreferencesHelper preferencesHelper, DatabaseHelper databaseHelper) {
    mIRemoteServer = server;
    mPreferencesHelper = preferencesHelper;
    mDatabaseHelper = databaseHelper;
    }

    public void loadData(String key, String day, BaseObserver observer) {
    Observable<SMResponse<ArrayList<TodayBean>>> today = mIRemoteServer.getToday(key, day);
    today.observeOn(AndroidSchedulers.mainThread())
    .subscribeOn(Schedulers.io())
    .subscribe(observer);
    }
  • 3、NetWorkPresenter定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    @ConfigPersistent
    public class NetWorkPresenter extends BasePresenter<NetWorkView> {

    private final DataManager mDataManager;

    private Disposable mDisposable;

    @Inject
    public NetWorkPresenter(DataManager dataManager) {
    mDataManager = dataManager;
    }

    @Override
    public void attachView(NetWorkView mvpView) {
    super.attachView(mvpView);
    }

    @Override
    public void detachView() {
    super.detachView();
    if (mDisposable != null) mDisposable.dispose();
    }
    public void loadData(String key,String day){
    //检查View是否附着在上面,不在直接抛出异常
    checkViewAttached();
    //检查是否往下运行
    dispose(mDisposable);
    mDataManager.loadData(key,day,new BaseObserver<SMResponse<ArrayList<TodayBean>>>(new SubscriberListener<SMResponse<ArrayList<TodayBean>>>() {

    @Override
    public void onSubscribe(Disposable disposable) {
    super.onSubscribe(disposable);
    mDisposable = disposable;
    }

    @Override
    public void onSuccess(SMResponse<ArrayList<TodayBean>> response) {
    getMvpView().getDataSuccess(response.result);
    }

    @Override
    public void onFail(String errorCode, String errorMsg) {
    getMvpView().getDataFail(errorCode,errorMsg);
    }

    @Override
    public void onError(Throwable e) {
    getMvpView().onError(e);
    }
    }));
    }
    }
  • 4、在Activity中的使用,通过Dagger2依赖注入NetWorkPresenter,同时在 onDestroy()中,销毁RxJava2正在调度的任务,个人理解的就是,关闭Activity,网络请求也有可能是在执行中,所以需要销毁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class NetWorkActivity extends BaseActivity implements NetWorkView, View.OnClickListener {

String key="b15674dbd34ec00ded57b369dfdabd90";
@Inject
NetWorkPresenter mMainPresenter;

private Button mBtn;
private EditText mDay;
private EditText mMonth;
private RecyclerView mRecyclerView;
private SMAdapter mSmAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityComponent().inject(this);
setContentView(R.layout.activity_net_work);
Timber.tag(getClassName()).i("mMainPresenter =%s",mMainPresenter);
mMainPresenter.attachView(this);
initView();
initListener();
}
private void initView() {
mBtn = (Button) findViewById(R.id.btn);
mMonth = (EditText) findViewById(R.id.et_month);
mDay = (EditText) findViewById(R.id.et_day);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
}
private void initListener() {
mBtn.setOnClickListener(this);
mSmAdapter = new SMAdapter(this, null);
mRecyclerView.setAdapter(mSmAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}

@Override
public void getDataFail(String errorCode, String errorMsg) {
Toast.makeText(this,errorMsg+errorCode,Toast.LENGTH_LONG).show();
}

@Override
public void onError(Throwable e) {
Toast.makeText(this,e.toString(),Toast.LENGTH_LONG).show();
}

@Override
public void getDataSuccess(ArrayList<TodayBean> result) {
String s = new Gson().toJson(result);
Timber.tag(getClassName()).i(s);
Thread thread = Thread.currentThread();
Timber.tag(getClassName()).i(thread.toString());
mSmAdapter.addData(result);
}
@Override
protected void onDestroy() {
super.onDestroy();
mMainPresenter.detachView();
}

@Override
public void onClick(View v) {
if (TextUtils.isEmpty(mMonth.getText())||TextUtils.isEmpty(mDay.getText())){
Toast.makeText(NetWorkActivity.this,"不能为空",Toast.LENGTH_SHORT).show();
}else {
mMainPresenter.loadData(key,mMonth.getText()+"/"+mDay.getText());
}
}
}

 上一篇
Hement:关于项目中的Dagger2的使用三 Hement:关于项目中的Dagger2的使用三
写在前面的话,要讲好这个Dagger2真的不是一件简单的事情 Dagger 1 :匕首 一个用于Android和Java的快速依赖注入。由SQUAR公司开发 Dagger 2:由谷歌公司接手开发 Dagger 2 依赖注入的原理 首先记
2018-12-07 Shiming_Li
下一篇 
Hement:MVP架构设计(一) Hement:MVP架构设计(一)
Hement : 取英文前字母,意思为快乐享受,希望我们在敲代码的工程中是快乐享受的意思 16年的时候我写过一篇博客基于Retorfit+Rxjava+Rxandroid的网络架构MVP网络框架(Retorfit+Rxjava+R
2018-12-04 Shiming_Li
  目录