美文网首页
Retrofit2(2.4.0)

Retrofit2(2.4.0)

作者: sofarsogoo_932d | 来源:发表于2018-03-29 20:58 被阅读0次

对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);
}

相关文章

网友评论

      本文标题:Retrofit2(2.4.0)

      本文链接:https://www.haomeiwen.com/subject/lfnscftx.html