1,昨天我們基本上把MVP給封裝起來了,今天接着昨天的東西來結合RxJava把Retrofit把網絡框架簡單的封裝一下,先看一下我們今天實現的效果:

哈哈 ,還是昨天的效果,好吧 ,我認錯。
2,由於這次是把RxJava給接入進來了,所以我們可以對昨天的BasePresenter再次進行封裝
BaseRxPresenter.java
package com.qianmo.myview2.base;
import rx.Subscription;
import rx.subscriptions.CompositeSubscription;
/**
* Created by wangjitao on 2016/11/9 0009.
* 基於Rx的Presenter的訂閱者的生命周期
*/
public class BaseRxPresenter<T extends BaseView> implements BasePresenter<T> {
protected T mView;
protected CompositeSubscription mCompositeSubscription;
protected void addSubscrebe(Subscription subscription) {
if (mCompositeSubscription == null) {
mCompositeSubscription = new CompositeSubscription();
}
mCompositeSubscription.add(subscription);
}
protected void unSubscribe() {
if (mCompositeSubscription != null) {
mCompositeSubscription.unsubscribe();
}
}
@Override
public void attachView(T view) {
this.mView = view;
}
@Override
public void detachView() {
this.mView = null;
unSubscribe();
}
}
將View的綁定和解綁方法在這里實現,並實現訂閱功能。
先看一下我們昨天沒有封裝的網絡請求
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
AppVersionService movieService = retrofit.create(AppVersionService.class);
movieService.getVersion()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<BaseResponse<VersionBean>>() {
@Override
public void onStart() {
mView.showProgressDialog();
}
@Override
public void onCompleted() {
mView.DissProgressDialog();
}
@Override
public void onError(Throwable e) {
mView.DissProgressDialog();
mView.ShowToast("請求出錯");
}
@Override
public void onNext(BaseResponse<VersionBean> versionBeanBaseResponse) {
if (Integer.valueOf(currentVersion.replace(".", "")) < Integer.valueOf(versionBeanBaseResponse.getData().getCode().replace(".", ""))) {
// mView.showUpdateDialog(versionBean);
//這里表示發現新版本
mView.ShowToast("發現最新版本");
} else {
//表示這就是最新版本
mView.ShowToast("已經是最新版本");
}
}
});
因為這只是我們的一個接口,如果是多個呢? 我們每一次都要new一個Retrofit對象嗎? 並且每次要請求網絡的時候都要重寫Subscriber的這四個onstart()、onCompleted()、onError()、onNext(),一般我們的Activity只關心最后的數據問題即它只想要我們Presenter最后返回給它Bean的數據進行出來就行,其它一切東西它並不是很想去只掉,好的,我們就可以幫它來解決這些問題
3,Retrofit的封裝
由上面的Retrofit我們知道,我們很不確定的是retrofit.create方法,因為有可能我們每次創建的APIService接口是不一樣的,所以這里我們可以這樣封裝一下
public <T> T create(Class<T> service) {
return mRetrofit.create(service);
}
然后我們每次並不想每次使用接口都去創建一個Retrofit對象,所以我們可以使用一個單例來解決
private static RetrofitManager sInstace;
/**
* 私有構造方法
*/
private RetrofitManager() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
// https://drakeet.me/retrofit-2-0-okhttp-3-0-config
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
builder.addInterceptor(loggingInterceptor);
}
File cacheFile = new File(Constant.PATH_CACHE);
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor cacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!SystemUtil.isNetworkConnected()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (SystemUtil.isNetworkConnected()) {
int maxAge = 0;
// 有網絡時, 不緩存, 最大保存時長為0
response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("Pragma")
.build();
} else {
// 無網絡時,設置超時為4周
int maxStale = 60 * 60 * 24 * 28;
response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
return response;
}
};
//設置緩存
builder.addNetworkInterceptor(cacheInterceptor);
builder.addInterceptor(cacheInterceptor);
builder.cache(cache);
//設置超時
builder.connectTimeout(10, TimeUnit.SECONDS);
builder.readTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS);
//錯誤重連
builder.retryOnConnectionFailure(true);
mOkHttpClient = builder.build();
mRetrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(Constant.BASE_URL)
.client(mOkHttpClient)
.build();
}
/**
* 創建單例
*/
public static RetrofitManager getInstace() {
if (sInstace == null) {
synchronized (RetrofitManager.class) {
sInstace = new RetrofitManager();
}
}
return sInstace;
}
可以看到,再創建的時候我們進行了一系列OkHttpClient和Retrofit的初始化,然后在上面的沒封裝的代碼中我們每一都要寫
movieService.getVersion()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
之類的代碼,所以我們在提供一個方法在封裝一下
public <T> void toSubscribe(Observable<T> o, Subscriber<T> s) {
o.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s);
}
ok,這樣我們的RetrofitManager差不多就封裝完畢了,再看看完整的代碼
RetrofitManager.java
package com.qianmo.myview2.network;
import android.content.Context;
import android.provider.SyncStateContract;
import com.qianmo.myview2.BuildConfig;
import com.qianmo.myview2.api.ZhiHuApi;
import com.qianmo.myview2.model.bean.DailyListBean;
import com.qianmo.myview2.model.bean.ThemeListBean;
import com.qianmo.myview2.utils.Constant;
import com.qianmo.myview2.utils.SystemUtil;
import java.io.File;
import java.io.IOException;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.util.concurrent.TimeUnit;
import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Created by wangjitao on 2016/11/9 0009.
* retrofit管理類
*/
public class RetrofitManager {
private static final int DEFAULT_TIMEOUT = 5;
private Retrofit mRetrofit;
private OkHttpClient mOkHttpClient;
private static RetrofitManager sInstace;
/**
* 私有構造方法
*/
private RetrofitManager() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
// https://drakeet.me/retrofit-2-0-okhttp-3-0-config
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
builder.addInterceptor(loggingInterceptor);
}
File cacheFile = new File(Constant.PATH_CACHE);
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor cacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!SystemUtil.isNetworkConnected()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (SystemUtil.isNetworkConnected()) {
int maxAge = 0;
// 有網絡時, 不緩存, 最大保存時長為0
response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("Pragma")
.build();
} else {
// 無網絡時,設置超時為4周
int maxStale = 60 * 60 * 24 * 28;
response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
return response;
}
};
//設置緩存
builder.addNetworkInterceptor(cacheInterceptor);
builder.addInterceptor(cacheInterceptor);
builder.cache(cache);
//設置超時
builder.connectTimeout(10, TimeUnit.SECONDS);
builder.readTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS);
//錯誤重連
builder.retryOnConnectionFailure(true);
mOkHttpClient = builder.build();
mRetrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(Constant.BASE_URL)
.client(mOkHttpClient)
.build();
}
/**
* 創建單例
*/
public static RetrofitManager getInstace() {
if (sInstace == null) {
synchronized (RetrofitManager.class) {
sInstace = new RetrofitManager();
}
}
return sInstace;
}
public Retrofit getRetrofit() {
return mRetrofit;
}
public <T> T create(Class<T> service) {
return mRetrofit.create(service);
}
public <T> void toSubscribe(Observable<T> o, Subscriber<T> s) {
o.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s);
}
}
把Retrofit的創建給解決了我們再看時解決每次重寫Subscriber的這四個onstart()、onCompleted()、onError()、onNext()的問題,由於這一塊我之前的博客寫過的,就不給大家廢話了,只是大致的說一下思路了,創建一個ProgressSubscriber.java讓它繼承自Subscriber,並添加網絡請求時所需要的加載框,在onStart()方法中顯示加載框,在onCompleted()、onError()影藏加載框,再通過接口回調將onNext()中產生的數據回調給presenter中去通知UI更新就行,直接上代碼了
ProgressSubscriber.java
package com.qianmo.myview2.network;
import android.content.Context;
import android.widget.Toast;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import rx.Subscriber;
/**
* Created by wangjitao on 2016/11/3 0003.
*/
public class ProgressSubscriber<T> extends Subscriber<T> implements ProgressCancelListener {
private SubscriberOnNextListenter mSubscriberOnNextListenter;
private ProgressDialogHandler mProgressDialogHandler;
private Context context;
public ProgressSubscriber(SubscriberOnNextListenter mSubscriberOnNextListenter, Context context) {
this.mSubscriberOnNextListenter = mSubscriberOnNextListenter;
this.context = context;
mProgressDialogHandler = new ProgressDialogHandler(context, this, true);
}
/**
* 在開始訂閱的時候顯示加載框
*/
@Override
public void onStart() {
if (mProgressDialogHandler != null) {
mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();
}
}
/**
* 在完成的時候進行隱藏
*/
@Override
public void onCompleted() {
Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
dismissProgressDialog();
}
/**
* 在出錯的時候也進行影藏
*
* @param e
*/
@Override
public void onError(Throwable e) {
if (e instanceof SocketTimeoutException) {
Toast.makeText(context, "網絡中斷,請檢查您的網絡狀態", Toast.LENGTH_SHORT).show();
} else if (e instanceof ConnectException) {
Toast.makeText(context, "網絡中斷,請檢查您的網絡狀態", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
dismissProgressDialog();
}
@Override
public void onNext(T t) {
mSubscriberOnNextListenter.next(t);
}
@Override
public void onCancelProgress() {
if (!this.isUnsubscribed()) {
this.unsubscribe();
}
}
private void showProgressDialog() {
if (mProgressDialogHandler != null) {
mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();
}
}
private void dismissProgressDialog() {
if (mProgressDialogHandler != null) {
mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget();
mProgressDialogHandler = null;
}
}
}
ProgressDialogHandler.java
package com.qianmo.myview2.network;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
/**
* Created by liukun on 16/3/10.
*/
public class ProgressDialogHandler extends Handler {
public static final int SHOW_PROGRESS_DIALOG = 1;
public static final int DISMISS_PROGRESS_DIALOG = 2;
private ProgressDialog pd;
private Context context;
private boolean cancelable;
private ProgressCancelListener mProgressCancelListener;
public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener,
boolean cancelable) {
super();
this.context = context;
this.mProgressCancelListener = mProgressCancelListener;
this.cancelable = cancelable;
}
private void initProgressDialog(){
if (pd == null) {
pd = new ProgressDialog(context);
pd.setCancelable(cancelable);
if (cancelable) {
pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
mProgressCancelListener.onCancelProgress();
}
});
}
if (!pd.isShowing()) {
pd.show();
}
}
}
private void dismissProgressDialog(){
if (pd != null) {
pd.dismiss();
pd = null;
}
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_PROGRESS_DIALOG:
initProgressDialog();
break;
case DISMISS_PROGRESS_DIALOG:
dismissProgressDialog();
break;
}
}
}
由於我們每次請求的時候有可能會出現一些請求的錯誤,,所以我們這里創建一個HttpResultFunc.java,來判斷這次請求是否成功
package com.qianmo.myview2.network;
import com.qianmo.myview2.response.BaseResponse;
import rx.functions.Func1;
/**
* Created by Administrator on 2016/11/9 0009.
*/
public class HttpResultFunc<T> implements Func1<BaseResponse<T>, T> {
@Override
public T call(BaseResponse<T> httpResult) {
if (httpResult.getCode() != 200) {
throw new ApiException(httpResult.getCode());
}
return httpResult.getData();
}
}
這樣基本上我們的東西就封裝的差不多了,再看一下我們的CheckVersion中調用代碼
Observable observable = RetrofitManager.getInstace()
.create(AppVersionService.class).getVersion()
.map(new HttpResultFunc<VersionBean>());
Subscription rxSubscription = new ProgressSubscriber<>(new SubscriberOnNextListenter<VersionBean>() {
@Override
public void next(VersionBean versionBean) {
mView.setUpdateText(versionBean.getDes());
}
}, context);
RetrofitManager.getInstace().toSubscribe(observable, (Subscriber) rxSubscription);
addSubscrebe(rxSubscription);
已經比較簡潔了(自我安慰中,小菜鳥畢竟技術有限),ok這樣網絡就大致的封裝好了,下一篇將Dagger加進來就差不多了
See You Next Time!
