开发者们现在都在使用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;
}
}
注释写的很清楚了,但是在添加header的时候,根据自己需要添加。
LocalApi是什么呢,在这个类里面我们定义请求方法,get,post等等,
public interface LocalApi {
//获取类别
@GET("classify")
Observable> getHealthClassify();
}
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 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);
}
}
这只是跟Retrofit绑定,真正的拿到数据,解析的json的在下面:
/**
* Created by hedong on 2016/4/19.
*/
public class GsonResponseBodyConverter implements Converter {
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;
}
}
}
在开始写后台的时候最好定好规范,以免造成不必要的麻烦。以上格式只是参考,使用者可自行修改。
我们也可以跟服务器约定错误类型,捕获异常:
/**
* 用于捕获服务器约定的错误类型
*/
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 extends Subscriber {
//对应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);
}
}
最后在Activity怎么调用呢,直接贴代码:
private void requestData() {
LocalService.getApi().getHealthClassify()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new AbsAPICallback>() {
@Override
protected void onDone(List list) {
//请求成功,做相应的页面操作
}
@Override
public void onError(Throwable e) {
super.onError(e);
//e.getMessage() 可获取服务器返回错误信息
}
});
}
ok,到此就结束了。
项目已上传:https://github.com/hedongBlog/MyNetHttp