Home - GilBert1987/RetrofitStudy GitHub Wiki
[[TOC]]
学习研究并最终实现基于Retrofit OkHttp 和RxJava Gson的Android 网络请求库
- 实现AuthToken的过期和二次自动获取机制 100%
- 实现基础的参数的自动加入 100%
- 实现参数的加密和签名 100%
- 支持GET POST 100%
- 实现一个NodeJs Server 模拟真实的服务器 100%
- 方便的支持Mock 40%
- 支持自定义Cache 100%
- 安装包大小测评
- 缓存机制深入研究
conn = (HttpURLConnection) myUrl.openConnection();
public URLConnection openConnection() throws IOException {
return streamHandler.openConnection(this);
}
/**
* Sets the stream handler factory for this VM.
*/
public static synchronized void setURLStreamHandlerFactory(URLStreamHandlerFactory factory) {
if (streamHandlerFactory != null) {
throw new Error("Factory already set");
}
streamHandlers.clear();
streamHandlerFactory = factory;
}
void setupStreamHandler() {
// Check for a cached (previously looked up) handler for
// the requested protocol.
streamHandler = streamHandlers.get(protocol);
if (streamHandler != null) {
return;
}
if (protocol.equals("http")) {
try {
String name = "com.android.okhttp.HttpHandler";
streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
} else if (protocol.equals("https")) {
try {
String name = "com.android.okhttp.HttpsHandler";
streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
} else if (protocol.equals("jar")) {
streamHandler = new JarHandler();
}
if (streamHandler != null) {
streamHandlers.put(protocol, streamHandler);
}
}
基于接口+注册
设置自己实现的 streamHandler + 反射 invoke 系统的handler
- Retrofit 是Square公司提供的高效的Http库,基于OK HTTP提供网络访问功能
- 将底层的代码都封装起来, 应用关注业务中的数据模型和操作方法
public interface IUserProfileService {
@FormUrlEncoded
@POST("/users/{user}/profile")
Call<ResultModel> updateUserProfile(@Field("userId") String userId, @Body UserProfile profile);
@Headers("Cache-Control: max-age=6400")
@GET("/users/{user}/profile")
Observable<Response<UserProfile>> getUserProfile(@Query("userId") String userId);
}
// 初始化OkHttp
OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder();
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
clientBuilder.addInterceptor(httpLoggingInterceptor);
clientBuilder.**addInterceptor**(new AddParamIterceptor());
CacheInterceptor cacheInterceptor = new CacheInterceptor(mContext);
clientBuilder.addInterceptor(new **SignatureIterceptor**()).addInterceptor(cacheInterceptor);
sOkHttpClient = clientBuilder.build();
cacheInterceptor.setCache(sOkHttpClient.cache());
// 初始化 retrofit
sRetrofit = new Retrofit.Builder().client(sOkHttpClient)
.baseUrl(API)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
//调用API
RetrofitUtil.getInstance(this)
.create(IUserProfileService.class)
.getUserProfile("498238400")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Response<UserProfile>>() {
});
public <T> T create(final Class<T> 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, Object... args)
throws Throwable {
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
- 通过adapter 实现,Gradle 中引入 compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
- 基于注册查找机制,returnType和CallAdapter对应
- 通过addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 注册
- 在运行时通过returnType和CallAdapter 的关系找到
动态查找
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
public interface CallAdapter<T> {
/**
* Returns the value type that this adapter uses when converting the HTTP response body to a Java
* object. For example, the response type for {@code Call<Repo>} is {@code Repo}. This type
* is used to prepare the {@code call} passed to {@code #adapt}.
* <p>
* Note: This is typically not the same type as the {@code returnType} provided to this call
* adapter's factory.
*/
Type responseType();
/**
* Returns an instance of {@code T} which delegates to {@code call}.
* <p>
* For example, given an instance for a hypothetical utility, {@code Async}, this instance would
* return a new {@code Async<R>} which invoked {@code call} when run.
* <pre><code>
* @Override
* public <R> Async<R> adapt(final Call<R> call) {
* return Async.create(new Callable<Response<R>>() {
* @Override
* public Response<R> call() throws Exception {
* return call.execute();
* }
* });
* }
* </code></pre>
*/
<R> T adapt(Call<R> call);
/**
* Creates {@link CallAdapter} instances based on the return type of {@linkplain
* Retrofit#create(Class) the service interface} methods.
*/
abstract class Factory {
/**
* Returns a call adapter for interface methods that return {@code returnType}, or null if it
* cannot be handled by this factory.
*/
public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
/**
* Extract the upper bound of the generic parameter at {@code index} from {@code type}. For
* example, index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
*/
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
/**
* Extract the raw class type from {@code type}. For example, the type representing
* {@code List<? extends Runnable>} returns {@code List.class}.
*/
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
By default, Retrofit can only deserialize HTTP bodies into OkHttp's ResponseBody type and it can only accept its RequestBody type for @Body.
Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Simple XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars
- OkHttp 使用List 管理Interceptor,按照先后顺序至执行
@Override public Response execute() throws IOException {
Response result = getResponseWithInterceptorChain();
}
private Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors())// 应用设置的Interceptor
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client)); // 执行真正的网络请求
if (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
// type是具体的类型 JavaBean.class
@Override
public Converter<ResponseBody, ?> responseBodyConverter(final Type type, Annotation[] annotations, Retrofit retrofit) {
Type newType = new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return new Type[] { type };
}
@Override
public Type getOwnerType() {
return null;
}
@Override
public Type getRawType() {
return ApiModel.class; //公共基类
}
};
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(newType));
return new GsonResponseBodyConverter<>(adapter);
}
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, Object> {
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(TypeAdapter<T> adapter) {
this.adapter = adapter;
}
@Override
public Object convert(ResponseBody value) throws IOException {
try {
ApiModel apiModel = (ApiModel) adapter.fromJson(value.charStream());
if (apiModel.mErrorCode == ErrorCode.TOKEN_NOT_EXIST) {
throw new TokenNotExistException();
} else if (apiModel.mErrorCode == ErrorCode.TOKEN_INVALID) {
throw new TokenInvalidException();
} else if (apiModel.mErrorCode != 0) {
// 特定 API 的错误,在相应的 Subscriber 的 onError 的方法中进行处理
throw new ApiException();
} else {
return apiModel.data;
}
} finally {
value.close();
}}
}
public class ApiModel<T> {
@SerializedName("error_code")
public int mErrorCode; // 链接成功,但服务器异常
@SerializedName("error_desc")
public String mErrorDesc; // 服务器异常的描述
public T data;
}
基于org.nanohttpd:nanohttpd:2.3.1 设置Interceptor 截断网络链接,读取本地文件。
- https://github.com/alighters/AndroidDemos
- npm modules express body-parsre