Skip to content
wangchen edited this page Mar 22, 2017 · 53 revisions

目的

学习研究并最终实现基于Retrofit OkHttp 和RxJava Gson的Android 网络请求库

已经完成的工作:

  • 实现AuthToken的过期和二次自动获取机制 100%
  • 实现基础的参数的自动加入 100%
  • 实现参数的加密和签名 100%
  • 支持GET POST 60%
  • 实现一个NodeJs Server 模拟真实的服务器 100%
  • 方便的支持Mock 40%
  • 支持自定义Cache 100%

#尚未完成

1. 题外话 URL Connection和 OkHttp 之间的关系?

对外接口

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

设计思想

基于接口+注册

问题:第三方Jar包怎么统一统计网络请求时间?

设置自己实现的 streamHandler + 反射 invoke 系统的handler

Retrofit 介绍及其API 简介

Retrofit 是什么

  • Retrofit 是Square公司提供的高效的Http库,基于OK HTTP提供网络访问功能
  • 将底层的代码都封装起来, 应用关注业务中的数据模型和操作方法

API 设计

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);
}
  • API 使用
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());
sRetrofit = new Retrofit.Builder().client(sOkHttpClient)
                        .baseUrl(API)
                        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

RetrofitUtil.getInstance(this)
      .get(IUserProfileService.class)
      .getUserProfile("498238400")
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(new Subscriber<Response<UserProfile>>() {
                });

###内部原理

  1. 动态代理
  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, Object... args)
              throws Throwable {
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
  1. CallAdapter

基于注册查找机制,returnType和CallAdapter对应 通过addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 注册,在运行时通过returnType和CallAdapter 的关系找到

/*
 * Copyright (C) 2015 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package retrofit2;

import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Adapts a {@link Call} into the type of {@code T}. Instances are created by {@linkplain Factory a
 * factory} which is {@linkplain Retrofit.Builder#addCallAdapterFactory(Factory) installed} into
 * the {@link Retrofit} instance.
 */
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>
   * &#64;Override
   * public &lt;R&gt; Async&lt;R&gt; adapt(final Call&lt;R&gt; call) {
   *   return Async.create(new Callable&lt;Response&lt;R&gt;&gt;() {
   *     &#64;Override
   *     public Response&lt;R&gt; 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);
    }
  }
}
  1. Converter 设计模式

###项目代码分析

会增加多大的安装包

依赖和参考项目

  1. https://github.com/alighters/AndroidDemos
  2. npm modules express body-parser

参考文献 http://expressjs.com/ https://github.com/alighters/AndroidDemos

Clone this wiki locally