对okhttp3进行封装的网络框架
github
1. 该框架用到的东西
该框架用了大量的注解
该框架依赖于okhttp3
2. 常用注解
1、@GET GET网络请求方式
2、@POST POST网络请求方式
3、@Headers() 头信息参数
4、@Path() 路径参数,替换url地址中 { } 所括的部分
5、@Query() 查询参数,将在url地址中追加类似“page=1”的字符串,形成提交给服务端的请求参数
6、@QueryMap 查询参数集合,将在url地址中追加类似
“type=text&username=abc&password=123”的字符串
7、@FormUrlEncoded 对表单域中填写的内容进行编码处理,避免乱码
8、@Field() 指定form表单域中每个空间的额name以及相应的数值
9、@FieldMap 表单域集合
10、@Multipart Post提交分块请求,如果上传文件,必须指定Multipart
11、@Body Post提交分块请求
12、@Url 替换包含baseUrl的请求地址
3. 用法
假设有一个接口
http://www.wanandroid.com/banner/json
3.1创建一个retrofit实例
Retrofit retrofit= new Retrofit.Builder()
.client(mClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(baseUrl)
.build();
参数说明
mClient
OkHttpClient,配置参考OkHttp
RxJavaCallAdapterFactory.create()
将Call转化为Observable
GsonConverterFactory.create()
将ResponseBody转化为具体的gson解析对应的实体类
baseUrl
接口的公共scheme
如上述接口,可以抽象为http://www.wanandroid.com/
3.2定义接口
public interface RetrofitHttpService {
@GET()
Call<ResponseBody> executGet(@Url String url);
@GET()
Call<ResponseBody> executGet(@Url String url, @QueryMap Map<String, String> maps);
@FormUrlEncoded
@POST()
Call<ResponseBody> executePost(@Url String url, @FieldMap Map<String, String> map);
@POST()
Call<ResponseBody> executeJsonPost(@Url String url, @Body RequestBody body);
@GET
Call<ResponseBody> loadBitmap(@Url String url);
@Streaming
@GET
Call<ResponseBody> downloadFile(@Url String url);
}
}
还有一种写法
public interface WeatherService {
@GET()
Call<ResponseBody> getWeatherData(@Url String url);
}
第二种写法强调的是获取天气数据这个接口,如果需要登录,则又需要新定义一个接口。第一种则是通用写法,所有的接口都可以用
3.3 接口调用
get请求
public void requestGetAsyn(String url, Map<String, String> params, final StringCallback callback) {
RetrofitHttpService service = RetrofitManager.getInstance().create(RetrofitHttpService.class);
Call<ResponseBody> call = service.executGet(url, params);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
callback.OnSuccess(response.body().string());
} catch (IOException e) {
e.printStackTrace();
callback.OnError("异常信息:" + e.getMessage());
}
} else {
callback.OnError("错误码:" + response.code());
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
if (t != null && t.getMessage() != null) {
callback.OnError(t.getMessage());
} else {
callback.OnError(ERROR);
}
}
});
}
post表单提交
public void requestPostAsyn(String url, Map<String, String> params, final StringCallback callback) {
RetrofitHttpService service = RetrofitManager.getInstance().create(RetrofitHttpService.class);
Call<ResponseBody> call = service.executePost(url, params);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
callback.OnSuccess(response.body().string());
} catch (IOException e) {
e.printStackTrace();
callback.OnError("异常信息:" + e.getMessage());
}
} else {
callback.OnError("错误码:" + response.code());
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
if (t != null && t.getMessage() != null) {
callback.OnError(t.getMessage());
} else {
callback.OnError(ERROR);
}
}
});
}
post提交json格式参数
public void requestPostJsonAsyn(String url, Map<String, String> params, final StringCallback callback) {
RetrofitHttpService service = RetrofitManager.getInstance().create(RetrofitHttpService.class);
MediaType JSON = MediaType.parse("application/json");
JSONObject jsonObject = new JSONObject(params);
RequestBody requestBody = RequestBody.create(JSON, jsonObject.toString());
Call<ResponseBody> call = service.executeJsonPost(url, requestBody);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
callback.OnSuccess(response.body().string());
} catch (IOException e) {
e.printStackTrace();
callback.OnError("异常信息:" + e.getMessage());
}
} else {
callback.OnError("错误码:" + response.code());
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
if (t != null && t.getMessage() != null) {
callback.OnError(t.getMessage());
} else {
callback.OnError(ERROR);
}
}
});
}
至此,retrofit的基本使用已经完事了。
3. 核心类分析
Retrofit
该类包含了下面这些参数
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
我们先来看看Retrofit的Builder这个内部类,这里面提供了许多设置上述参数的方法,就不说了,主要来看看build这个方法。
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
分析(自上而下看代码)
当baseUrl为null时,会抛异常
callFactory这个其实指的就是OkHttpClient(继承自Call.Factory),当我们没有显示设置时,则会使用默认的client,为了更加方便的控制网络,建议设置一个自定义的client,比如设置超时时间,拦截器,缓存等。
callbackExecutor,我们来看一下默认的执行器
Platform
该类主要是获取当前程序是java还是android
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
明显看出默认的Executor,在主线程中。这就是为什么retrofit不用切换到主线程去返回报文,因为报文的回调方法已经在主线程了。
callAdapterFactories
看代码,CallAdapter是接口,Factory是该接口的一个内部抽象类
不论我们有木有addCallAdapterFactory,都会增加一个默认的实现
ExecutorCallAdapterFactory,该类继承CallAdapter.Factory,该实现放在自定义CallAdapter之后
ExecutorCallAdapterFactory
我们只看关键代码
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
从这里就看出了报文是从哪个地方返回的
converterFactories
看代码,Converter是接口,Factory是该接口的一个内部抽象类
无论我们有木有addConverterFactory,都会有一个默认的实现
BuiltInConverters,该类继承Converter. Factory,该实现添加在自定义的Converter之前。
BuiltInConverters
第一次看这个类的时候不知道它有何用,稍后在来解析。
在来看下mRetrofit.create(service)这个方法
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
这里用到了jdk动态代理方法,根据传递的接口返回一个动态代理,当我们调用接口的方法时,就会调用invoke方法
从前面我们知道Retrofit有一个serviceMethodCache,里面保存了一系列的serviceMethod,而serviceMethod包含了http请求相关的信息
ServiceMethod
static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
private final okhttp3.Call.Factory callFactory;
private final CallAdapter<R, T> callAdapter;
private final HttpUrl baseUrl;
private final Converter<ResponseBody, R> responseConverter;
private final String httpMethod;
private final String relativeUrl;
private final Headers headers;
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
再看invoke方法的最后三行代码
每调用接口中的一个方法,如果是第一次调用该方法会根据当前的retrofit和method构建出一个serviceMethod对象,并将其保存在缓存中,下次就直接从缓存中区。
根据这个serviceMethod构建出一个okHttpCall。
最后一句代码,把一个okHttpCall 类型适配为用户定义的 service method 的 return type
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
这个callAdapter是一个接口,最终会调用它的实现类的adapt方法,如RxJavaCallAdapterFactory,它的adapt方法
public <R> Observable<Result<R>> adapt(Call<R> call) {
Observable<Result<R>> observable = Observable.create(new CallOnSubscribe<>(call)) //
.map(new Func1<Response<R>, Result<R>>() {
@Override public Result<R> call(Response<R> response) {
return Result.response(response);
}
}).onErrorReturn(new Func1<Throwable, Result<R>>() {
@Override public Result<R> call(Throwable throwable) {
return Result.error(throwable);
}
});
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
在看ExecutorCallAdapterFactory(默认的callAdapter)的adapt方法
public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
我们这里只探讨ExecutorCallAdapterFactory方式的返回类型Call,调动call.enqueue
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
这里的delegate.enqueue,其中delegate是Call这个接口,它的实现类是OkHttpCall,因此最终调用的就是OkHttpCall的enqueue方法,该方法最终调用的OkHttpClient的Call.enqueue方法,至此就将交易发了出去。
4. 总结
主要关注2和3
Retrofit的回调已经放在UI线程,无需再转化线程
图片请求和文件下载
一般我们会选择一个图片框架
如果用Retrofit请求图片和下载文件,只需要将response转化为流即可
response.body().byteStream() //文件流
responseBody.contentLength() //总长度
对于图片,通过Bitmap工具类可以直接将流转化为bitmap
对于文件,将流保存在对应的文件目录即可,同时通过已下载的文件流字节数/总长度来计算进度
InputStream is = response.body().byteStream();
byte[] buf = new byte[1024];
long total = responseBody.contentLength();
while ((len = is.read(buf)) != -1) {
sum += len;
fos.write(buf, 0, len);
callback.Progress(sum * 1.0f / total * 100);
}
网友评论