开发者们现在都在使用OkHttp了,在很多借鉴之后,现在也来封装属于自己的网络请求框架。
该框架使用Retrofit,OkHttp,RxJava,RxAndroid,Gson一起封装。
客户端请求一般分为如下几步:
通过API向服务器发送请求——->服务器收到请求然后响应(这里有两种情况,一是请求成功返回Json数据,二是去请求失败返回失败状态)———->客服端拿到服务器返回状态解析数据或者请求失败提示用户
根据以上思路来看代码:
- import android.os.Build;
- import java.io.IOException;
- import java.util.concurrent.TimeUnit;
- import okhttp3.Interceptor;
- import okhttp3.OkHttpClient;
- import okhttp3.Request;
- import okhttp3.Response;
- import okhttp3.logging.HttpLoggingInterceptor;
- import retrofit2.Retrofit;
- import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
- /**
- * Created by hedong on 2016/4/19.
- */
- public class LocalService {
- public static final String API_BASE_URL = “http://www.tngou.net/api/info/”;//主Api路径
- private static final LocalApi service = getRetrofit().create(LocalApi.class);
- private static Retrofit mRetrofit;
- private static OkHttpClient mOkHttpClient;
- public final static int CONNECT_TIMEOUT = 60; //设置连接超时时间
- public final static int READ_TIMEOUT = 60; //设置读取超时时间
- public final static int WRITE_TIMEOUT = 60; //设置写的超时时间
- private static OkHttpClient genericClient() {
- HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
- interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
- OkHttpClient httpClient = new OkHttpClient.Builder()
- .addNetworkInterceptor(interceptor)
- .retryOnConnectionFailure(true)
- .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)//设置读取超时时间
- .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)//设置写的超时时间
- .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)//设置连接超时时间
- .addInterceptor(new Interceptor() {
- @Override
- public Response intercept(Chain chain) throws IOException {
- Request request = chain.request()
- .newBuilder()
- .addHeader(”source-terminal”, “Android”) //操作系统名称(注:ios、android)//设备型号
- .addHeader(”device-model”, Build.MODEL) //设备型号
- .addHeader(”os-version”, Build.VERSION.RELEASE)//操作系统版本号
- //.addHeader(“app-name”, name);//应用名称
- .build();
- return chain.proceed(request);
- }
- }).build();
- return httpClient;
- }
- public static LocalApi getApi() {
- return service;
- }
- protected static Retrofit getRetrofit() {
- if (null == mRetrofit) {
- if (null == mOkHttpClient) {
- mOkHttpClient = genericClient();
- }
- mRetrofit = new Retrofit.Builder()
- .baseUrl(API_BASE_URL)
- .addConverterFactory(ResponseConverterFactory.create())
- .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
- .client(mOkHttpClient)
- .build();
- }
- return mRetrofit;
- }
- }
import android.os.Build;import java.io.IOException;
import java.util.concurrent.TimeUnit;import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;/*** Created by hedong on 2016/4/19.*/
public class LocalService {public static final String API_BASE_URL = "http://www.tngou.net/api/info/";//主Api路径private static final LocalApi service = getRetrofit().create(LocalApi.class);private static Retrofit mRetrofit;private static OkHttpClient mOkHttpClient;public final static int CONNECT_TIMEOUT = 60; //设置连接超时时间public final static int READ_TIMEOUT = 60; //设置读取超时时间public final static int WRITE_TIMEOUT = 60; //设置写的超时时间private static OkHttpClient genericClient() {HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);OkHttpClient httpClient = new OkHttpClient.Builder().addNetworkInterceptor(interceptor).retryOnConnectionFailure(true).readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)//设置读取超时时间.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)//设置写的超时时间.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)//设置连接超时时间.addInterceptor(new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request().newBuilder().addHeader("source-terminal", "Android") //操作系统名称(注:ios、android)//设备型号.addHeader("device-model", Build.MODEL) //设备型号.addHeader("os-version", Build.VERSION.RELEASE)//操作系统版本号//.addHeader("app-name", name);//应用名称.build();return chain.proceed(request);}}).build();return httpClient;}public static LocalApi getApi() {return service;}protected static Retrofit getRetrofit() {if (null == mRetrofit) {if (null == mOkHttpClient) {mOkHttpClient = genericClient();}mRetrofit = new Retrofit.Builder().baseUrl(API_BASE_URL).addConverterFactory(ResponseConverterFactory.create()).addCallAdapterFactory(RxJavaCallAdapterFactory.create()).client(mOkHttpClient).build();}return mRetrofit;}
}
注释写的很清楚了,但是在添加header的时候,根据自己需要添加。
LocalApi是什么呢,在这个类里面我们定义请求方法,get,post等等,
- public interface LocalApi {
- //获取类别
- @GET(“classify”)
- Observable<List<HealthClassifyBean>> getHealthClassify();
- }
public interface LocalApi {//获取类别@GET("classify")Observable<List<HealthClassifyBean>> getHealthClassify();}
请求发出去了,看一下怎么解析返回的json数据呢,自定义ResponseConverterFactory继承自Converter.Factory
- public class ResponseConverterFactory extends Converter.Factory {
- public static ResponseConverterFactory create() {
- return create(new Gson());
- }
- public static ResponseConverterFactory create(Gson gson) {
- return new ResponseConverterFactory(gson);
- }
- private final Gson gson;
- private ResponseConverterFactory(Gson gson) {
- if (gson == null) throw new NullPointerException(“gson == null”);
- this.gson = gson;
- }
- @Override
- public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
- return new GsonResponseBodyConverter<>(gson, type);
- }
- @Override
- public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
- return new GsonResponseBodyConverter<>(gson, type);
- }
- }
public class ResponseConverterFactory extends Converter.Factory {public static ResponseConverterFactory create() {return create(new Gson());}public static ResponseConverterFactory create(Gson gson) {return new ResponseConverterFactory(gson);}private final Gson gson;private ResponseConverterFactory(Gson gson) {if (gson == null) throw new NullPointerException("gson == null");this.gson = gson;}@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {return new GsonResponseBodyConverter<>(gson, type);}@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {return new GsonResponseBodyConverter<>(gson, type);}
}
这只是跟Retrofit绑定,真正的拿到数据,解析的json的在下面:
- /**
- * Created by hedong on 2016/4/19.
- */
- public class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
- private final Gson gson;
- private final Type type;
- public GsonResponseBodyConverter(Gson gson, Type type) {
- this.gson = gson;
- this.type = type;
- }
- /**
- * {
- * “status”: true,
- * “data”: [
- * {
- * “description”: ”“,
- * “id”: 6,
- * “keywords”: ”“,
- * “name”: ”“,
- * “seq”: 1,
- * “title”: ”“
- * },
- * {
- * “description”: ”“,
- * “id”: 5,
- * “keywords”: ”“,
- * “name”: ”“,
- * “seq”: 2,
- * “title”: ”“
- * }
- * ]
- * }
- *
- * @param value
- * @return
- * @throws IOException
- */
- @Override
- public T convert(ResponseBody value) throws IOException {
- String response = value.string();
- Log.d(”Network”, “response>>” + response);
- try {
- JSONObject jsonObject = new JSONObject(response);
- if (jsonObject.getString(“status”).equals(“true”)) {
- //result==true表示成功返回,继续用本来的Model类解析
- String data = jsonObject.getString(”data”);
- return gson.fromJson(data, type);
- } else {
- //ErrResponse 将msg解析为异常消息文本
- ErrResponse errResponse = gson.fromJson(response, ErrResponse.class);
- throw new ResultException(0, errResponse.getMsg());
- }
- } catch (JSONException e) {
- e.printStackTrace();
- Log.e(”Network”, e.getMessage());
- return null;
- }
- }
- }
/*** Created by hedong on 2016/4/19.*/
public class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {private final Gson gson;private final Type type;public GsonResponseBodyConverter(Gson gson, Type type) {this.gson = gson;this.type = type;}/*** {* "status": true,* "data": [* {* "description": "",* "id": 6,* "keywords": "",* "name": "",* "seq": 1,* "title": ""* },* {* "description": "",* "id": 5,* "keywords": "",* "name": "",* "seq": 2,* "title": ""* }* ]* }** @param value* @return* @throws IOException*/@Overridepublic T convert(ResponseBody value) throws IOException {String response = value.string();Log.d("Network", "response>>" + response);try {JSONObject jsonObject = new JSONObject(response);if (jsonObject.getString("status").equals("true")) {//result==true表示成功返回,继续用本来的Model类解析String data = jsonObject.getString("data");return gson.fromJson(data, type);} else {//ErrResponse 将msg解析为异常消息文本ErrResponse errResponse = gson.fromJson(response, ErrResponse.class);throw new ResultException(0, errResponse.getMsg());}} catch (JSONException e) {e.printStackTrace();Log.e("Network", e.getMessage());return null;}}
}
这里解释一下:
在开始写后台的时候最好定好规范,以免造成不必要的麻烦。以上格式只是参考,使用者可自行修改。
我们也可以跟服务器约定错误类型,捕获异常:
- /**
- * 用于捕获服务器约定的错误类型
- */
- public class ResultException extends RuntimeException {
- private int errCode = 0;
- public ResultException(int errCode, String msg) {
- super(msg);
- this.errCode = errCode;
- }
- public int getErrCode() {
- return errCode;
- }
- }
/*** 用于捕获服务器约定的错误类型*/
public class ResultException extends RuntimeException {private int errCode = 0;public ResultException(int errCode, String msg) {super(msg);this.errCode = errCode;}public int getErrCode() {return errCode;}
}
自定义回调,获取http请求对应的状态码:
- public abstract class AbsAPICallback<T> extends Subscriber<T> {
- //对应HTTP的状态码
- private static final int UNAUTHORIZED = 401;
- private static final int FORBIDDEN = 403;
- private static final int NOT_FOUND = 404;
- private static final int REQUEST_TIMEOUT = 408;
- private static final int INTERNAL_SERVER_ERROR = 500;
- private static final int BAD_GATEWAY = 502;
- private static final int SERVICE_UNAVAILABLE = 503;
- private static final int GATEWAY_TIMEOUT = 504;
- protected AbsAPICallback() {
- }
- @Override
- public void onError(Throwable e) {
- Throwable throwable = e;
- //获取最根源的异常
- while (throwable.getCause() != null) {
- e = throwable;
- throwable = throwable.getCause();
- }
- if (e instanceof HttpException) { //HTTP错误
- HttpException httpException = (HttpException) e;
- switch (httpException.code()) {
- case UNAUTHORIZED:
- case FORBIDDEN:
- case NOT_FOUND:
- case REQUEST_TIMEOUT:
- case GATEWAY_TIMEOUT:
- case INTERNAL_SERVER_ERROR:
- case BAD_GATEWAY:
- case SERVICE_UNAVAILABLE:
- default:
- //Toast.makeText(App.getInstance(), R.string.server_http_error, Toast.LENGTH_SHORT).show();
- break;
- }
- } else if (e instanceof SocketTimeoutException) {
- //Toast.makeText(App.getInstance(), R.string.network_error, Toast.LENGTH_SHORT).show();
- } else if (e instanceof ResultException) { //服务器返回的错误
- ResultException resultException = (ResultException) e;
- // Toast.makeText(App.getInstance(), resultException.getMessage(), Toast.LENGTH_SHORT).show();
- } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) {
- // Toast.makeText(App.getInstance(), R.string.data_error, Toast.LENGTH_SHORT).show(); //均视为解析错误
- } else if(e instanceof ConnectException){
- // Toast.makeText(App.getInstance(), R.string.server_http_error, Toast.LENGTH_SHORT).show();
- } else { //未知错误
- }
- onCompleted();
- }
- protected abstract void onDone(T t);
- @Override
- public void onCompleted() {
- }
- @Override
- public void onNext(T t) {
- onDone(t);
- }
- }
public abstract class AbsAPICallback<T> extends Subscriber<T> {//对应HTTP的状态码private static final int UNAUTHORIZED = 401;private static final int FORBIDDEN = 403;private static final int NOT_FOUND = 404;private static final int REQUEST_TIMEOUT = 408;private static final int INTERNAL_SERVER_ERROR = 500;private static final int BAD_GATEWAY = 502;private static final int SERVICE_UNAVAILABLE = 503;private static final int GATEWAY_TIMEOUT = 504;protected AbsAPICallback() {}@Overridepublic void onError(Throwable e) {Throwable throwable = e;//获取最根源的异常while (throwable.getCause() != null) {e = throwable;throwable = throwable.getCause();}if (e instanceof HttpException) {//HTTP错误HttpException httpException = (HttpException) e;switch (httpException.code()) {case UNAUTHORIZED:case FORBIDDEN:case NOT_FOUND:case REQUEST_TIMEOUT:case GATEWAY_TIMEOUT:case INTERNAL_SERVER_ERROR:case BAD_GATEWAY:case SERVICE_UNAVAILABLE:default://Toast.makeText(App.getInstance(), R.string.server_http_error, Toast.LENGTH_SHORT).show();break;}} else if (e instanceof SocketTimeoutException) {//Toast.makeText(App.getInstance(), R.string.network_error, Toast.LENGTH_SHORT).show();} else if (e instanceof ResultException) {//服务器返回的错误ResultException resultException = (ResultException) e;// Toast.makeText(App.getInstance(), resultException.getMessage(), Toast.LENGTH_SHORT).show();} else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) {// Toast.makeText(App.getInstance(), R.string.data_error, Toast.LENGTH_SHORT).show(); //均视为解析错误} else if(e instanceof ConnectException){// Toast.makeText(App.getInstance(), R.string.server_http_error, Toast.LENGTH_SHORT).show();} else {//未知错误}onCompleted();}protected abstract void onDone(T t);@Overridepublic void onCompleted() {}@Overridepublic void onNext(T t) {onDone(t);}
}
代码里面都注释很清楚。
最后在Activity怎么调用呢,直接贴代码:
- private void requestData() {
- LocalService.getApi().getHealthClassify()
- .subscribeOn(Schedulers.io())
- .observeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new AbsAPICallback<List<HealthClassifyBean>>() {
- @Override
- protected void onDone(List<HealthClassifyBean> list) {
- //请求成功,做相应的页面操作
- }
- @Override
- public void onError(Throwable e) {
- super.onError(e);
- //e.getMessage() 可获取服务器返回错误信息
- }
- });
- }
private void requestData() {LocalService.getApi().getHealthClassify().subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new AbsAPICallback<List<HealthClassifyBean>>() {@Overrideprotected void onDone(List<HealthClassifyBean> list) {//请求成功,做相应的页面操作}@Overridepublic void onError(Throwable e) {super.onError(e);//e.getMessage() 可获取服务器返回错误信息}});}
ok,到此就结束了。
项目已上传:https://github.com/hedongBlog/MyNetHttp
转自何东_hd的博客:http://blog.csdn.net/hedong_77/article/details/53607245