最近公司要开始新项目,准备换掉之前的网络框架。正好最近在看Retrofit+RxJava,感觉还是非常好用的,于是准备将网络框架替换为Retrofit+RxJava+OkHttp。
Retrofit+RxJava的优点很明显:可以实现线程之间的快速切换;处理数据简洁易懂,易于进行元素间的变换;可以简单处理大量的嵌套异步回调等。但是使用Retrofit+RxJava+OkHttp完成一次网络请求还是需要写很多代码的,所以肯定是需要再次封装的。这里我根据项目的特点对Retrofit+RxJava+OkHttp进行了封装,优点是调用方便,代码量少,链式结构清晰。当然,本文只是提供了一种封装方式,只有适合自己项目的封装才是最好的封装~
关于Retrofit+RxJava的基本用法,本文不作详细介绍,可以参考
Retrofit官方文档
给 Android 开发者的 RxJava 详解
先来看一下调用的代码:
private void doHttpRequest() {
HttpManager.getInstance()
.with(this)
.setObservable(RetrofitManager.getService().getExpress("yuantong", "200382770316"))
.setDataListener(new HttpDataListener<List<Express>>() {
@Override
public void onNext(List<Express> list) {
//这里对返回数据进行处理
}
});
}
怎么样,是不是很简单┑( ̄Д  ̄)┍ 几行代码就完成了一次网络请求,使用时只需要传递上下文Context、向接口传递的参数以及返回数据的类型,就可以直接对数据进行处理了!
下面来看一下封装的过程和思路:
常见的接口返回数据的格式一般是这个样子的
{
"status": 200,
"message": "success",
"data": {
//具体的业务数据
}
}
我们希望的封装是这样的:对status和判断和message的处理进行封装,在调用时,我们只关心请求成功后返回的数据,只需要在请求成功后对返回的对象进行处理,而请求失败或者其他情况全部进行封装,不在调用时处理。
测试使用的是快递100的测试接口:
http://www.kuaidi100.com/query?type=yuantong&postid=200382770316
来看一下代码~首先是build.gradle文件:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'com.squareup.retrofit2:retrofit:2.0.1'
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
compile 'com.squareup.retrofit2:adapter-rxjava2:+'
compile 'com.google.code.gson:gson:2.2.4'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
}
引入了Retrofit、RxJava、RxAndroid、OkHttp等相关库。
然后是Retrofit的管理类:
public class RetrofitManager {
public static final String url = "http://www.kuaidi100.com/";
private static final int TIMEOUT = 15;
private HttpService httpService;
private volatile static RetrofitManager singleton;
private boolean debugMode;
private RetrofitManager() {
//OkHttp初始化
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(TIMEOUT, TimeUnit.SECONDS);
//debug模式打印网络请求日志
if (debugMode){
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(logging);
}
//Retrofit初始化
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(url)
.build();
httpService = retrofit.create(HttpService.class);
}
public static RetrofitManager getInstance() {
if (singleton == null) {
synchronized (RetrofitManager.class) {
if (singleton == null) {
singleton = new RetrofitManager();
}
}
}
return singleton;
}
public static HttpService getService(){
return getInstance().httpService;
}
}
Retrofit本身不具备http标准网络访问基础,所以还是需要依赖OkHttp进行网络访问。在RetrofitManager类中对OkHttp和Retrofit进行了初始化,同时实例化一个HttpService对象。
HttpService:
public interface HttpService {
@GET("query")
Observable<ResultModel<List<Express>>> getExpress(@Query("type") String type,
@Query("postid") String postid);
}
我们知道,RxJava的基本实现是Observable.subscribe(Observer),通过以上代码我们可以创建出一个Observable对象。那么接下来就需要封装出一个Observer。
返回结果的基础类,统一处理status和message
public class ResultModel<T> {
private String status;//200成功
private String message;
private T data;
}
转换类,利用RxJava的map方法,对ResultModel进行处理后转换为业务实体类
public class ResultMap<T> implements Function<ResultModel<T>, T> {
@Override
public T apply(ResultModel<T> httpResult) {
if ("200".equals(httpResult.getStatus())) {
return httpResult.getData();
} else {
throw new RuntimeException("请求失败(code=" + httpResult.getStatus() + ",message=" + httpResult.getMessage() + ")");
}
}
}
Observer封装,显示一个ProgressDialog,同时在请求失败时在OnError回调方法中对错误信息进行处理,在请求成功OnNext回调方法中交给调用者处理。
public class HttpObserver<T> implements Observer<T> {
private HttpDataListener mSubscriberOnNextListener;
private WeakReference<Context> context;
private ProgressDialog dialog;
public HttpObserver(HttpDataListener mSubscriberOnNextListener, Context context) {
this.mSubscriberOnNextListener = mSubscriberOnNextListener;
this.context = new WeakReference<>(context);
initProgressDialog();
}
//自定义ProgressDialog提示文字
public HttpObserver(HttpDataListener mSubscriberOnNextListener, Context context, String message) {
this.mSubscriberOnNextListener = mSubscriberOnNextListener;
this.context = new WeakReference<>(context);
initProgressDialog(message);
}
//自定义ProgressDialog
public HttpObserver(HttpDataListener mSubscriberOnNextListener, Context context, ProgressDialog dialog) {
this.mSubscriberOnNextListener = mSubscriberOnNextListener;
this.context = new WeakReference<>(context);
this.dialog = dialog;
}
private void initProgressDialog() {
Context context = this.context.get();
if (dialog == null && context != null) {
dialog = new ProgressDialog(context);
dialog.setMessage("加载中……");
dialog.setCancelable(false);
}
}
private void initProgressDialog(String message) {
Context context = this.context.get();
if (dialog == null && context != null) {
dialog = new ProgressDialog(context);
dialog.setMessage(message);
dialog.setCancelable(false);
}
}
private void showProgressDialog() {
Context context = this.context.get();
if (dialog == null || context == null) return;
if (!dialog.isShowing()) {
dialog.show();
}
}
private void dismissProgressDialog() {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
}
@Override
public void onSubscribe(Disposable d) {
showProgressDialog();
}
@Override
public void onComplete() {
dismissProgressDialog();
}
@Override
public void onError(Throwable e) {
Context context = this.context.get();
if (context == null) return;
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, e.getMessage(), Toast.LENGTH_SHORT).show();
Log.d("http", "error----------->" + e.toString());
}
dismissProgressDialog();
}
@Override
public void onNext(T t) {
if (mSubscriberOnNextListener != null) {
mSubscriberOnNextListener.onNext(t);
}
}
}
Http请求管理类
public class HttpManager {
private volatile static HttpManager singleton;
private WeakReference<Context> context;
private Observable observable;
private HttpObserver observer;
private HttpManager() {
}
public static HttpManager getInstance() {
if (singleton == null) {
synchronized (HttpManager.class) {
if (singleton == null) {
singleton = new HttpManager();
}
}
}
return singleton;
}
public HttpManager with(Context context) {
this.context = new WeakReference<>(context);
return singleton;
}
public HttpManager setObservable(Observable observable) {
this.observable = observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new ResultMap());
return singleton;
}
//创建subscriber
public void setDataListener(HttpDataListener listener) {
observer = new HttpObserver(listener, context.get());
observable.subscribe(observer);
}
//创建subscriber 自定义ProgressDialog的文字
public void setDataListener(HttpDataListener listener, String message) {
observable.subscribe(new HttpObserver(listener, context.get(), message));
}
//创建subscriber 自定义ProgressDialog
public void setDataListener(HttpDataListener listener, ProgressDialog dialog) {
observable.subscribe(new HttpObserver(listener, context.get(), dialog));
}
}
以上,Retrofit+RxJava+OkHttp的封装就完成了。再来回顾一下Http请求的调用:
public class MainActivity extends Activity {
private TextView data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
data = (TextView) findViewById(R.id.data);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doHttpRequest();
}
});
}
private void doHttpRequest() {
HttpManager.getInstance()
.with(this)
.setObservable(RetrofitManager.getService().getExpress("yuantong", "200382770316"))
.setDataListener(new HttpDataListener<List<Express>>() {
@Override
public void onNext(List<Express> list) {
//这里对返回数据进行处理
String result = "";
for (int i = 0; i < list.size(); i++){
result = result + list.get(i).toString();
}
data.setText(result);
}
});
}
}
网友评论
java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
试试把 .addConverterFactory(GsonConverterFactory.create())
改成 .addConverterFactory(GsonConverterFactory.create(new Gson()))