加入依賴
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
:經過GsonConverterFactory
爲Retrofit
添加Gson
支持
logging-interceptor
:能夠很直觀的觀察到網絡請求的日記
adapter-rxjava2
:一個用於適應RXJava 2
類型的適配器。
搭建網絡框架
public interface IMvpView {
/**
* 數據失敗的同一處理
* @param errorCode
* @param errorMsg
*/
void getDataFail(String errorCode, String errorMsg);
/**
* 發成異常的同一處理
* @param e
*/
void onError(Throwable e);
}
複製代碼
public interface IPresenter<V extends IMvpView> {
/**
* 和view結合
* @param mvpView
*/
void attachView(V mvpView);
/**
* 和view 斷開
*/
void detachView();
}
複製代碼
BasePresenter
全部Presenter
的基類,同時綁定全部Activity
的生命週期
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架構設計(一)
能夠知道DataManager
不單單是處理網絡請求那麼簡單,同時還須要處理本地存儲SharedPreferences
和SQLite
因此就轉變成了,DataManager向外界提供數據對象,數據的處理已經幫您處理好了,使用的時候只須要獲取你想要的對象實例,就能夠了,具體封裝以下
@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();
}
}
複製代碼
網絡框架如何使用
這裏使用的是聚合數據的接口 ,在這裏感謝無私的貢獻,三年了這個接口還能用,萬分感謝
http://v.juhe.cn/todayOnhistory/queryEvent.php?key=b15674dbd34ec00ded57b369dfdabd90&date=1/1
複製代碼
一、定義遠程Server:IRemoteServer
,在這裏我把之前的單獨生成的Retrofit
的Server
抽取到IRemoteServer
,由於項目使用了Dagger2
,後面介紹
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);
}
}
}
複製代碼
二、DataManager
中的線程調度,結果回調到AndroidSchedulers.mainThread()
線程,就是安卓的UI
線程。
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);
}
複製代碼
@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);
}
}));
}
}
複製代碼
四、在Activity
中的使用,經過Dagger2依賴注入NetWorkPresenter
,同時在 onDestroy()
中,銷燬RxJava2
正在調度的任務,我的理解的就是,關閉Activity,網絡請求也有多是在執行中,因此須要銷燬。
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);
set ContentView(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());
}
}
}
複製代碼