1. 程式人生 > 實用技巧 >shell函式和陣列概念(包含案例)

shell函式和陣列概念(包含案例)

十分鐘教你手擼一個簡單的Retrofit demo

眾所周知,retrofit框架是square公司旗下的著名的http請求框架,今天我們來理一理它的主要邏輯,並寫一個demo,這裡涉及到java中註解,反射,泛型等知識點和構建者模式、動態代理,和我一起來一探究竟吧。

Retrofit的具體用法請自行百度,下面是關鍵的三行程式碼

//利用構建者模式例項化Retrofit    
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://restapi.amap.com/").build();
//通過動態代理生成介面的例項物件,並實現介面中定義的方法;
apiService = (ApiService) retrofit.create(ApiService.class);
//代理物件去做http請求
Call call = (Call) apiService.get("110101","ae6c53e2186f33bbf240a12d80672d1b");

先想一想做http請求,我們需要什麼?需要域名,請求方式,請求引數,嗯,還需要Okhttp

實現Retrofit第一步

構建MyRetrofit類,在裡邊兒定義一個內部Builder類,構建者模式是將一個複雜的物件一步一步建立起來。然後在Builder型別中baseUrl方法準備好域名,callFactory準備好OKHttp ,build()方法將獲得的引數傳入MyRetrofit構造方法,返回MyRetrofit例項物件。


public class MyRetrofit {
​
  public final HttpUrl baseUrl;
  public final Call.Factory factory;
​
  public MyRetrofit(HttpUrl baseUrl, Call.Factory factory){
    this.baseUrl = baseUrl;
    this.factory = factory;
   }
​
  public static final class Builder{
    private HttpUrl baseUrl;
    private Call.Factory factory;
​
    public Builder baseUrl(String url){
      if(url != null){
        baseUrl = HttpUrl.get(url);
       }
      return this;
     }
    
    public Builder callFactory(Call.Factory factory){
      if(factory != null){
        this.factory = factory;
       }
      return this;
     }
​
    public MyRetrofit build(){
      if(this.factory == null){
        this.factory = new OkHttpClient();
       }
      return new MyRetrofit(baseUrl,factory);
     }
   }
}

實現Retrofit第二步

通過介面建立代理物件, 並在invoke的回撥中實現apiService中定義的方法。代理模式是類似於中介代理的某項服務,類似於租房,你不需要知道房東是誰,只需要找中介就能租,靜態代理是租房找租房中介,留學找留學中介,相親找媒婆;而動態代理就很牛了,不管是租房,留學還是相親都可以找這個中介,即靜態代理是一個代理功能對應一個代理類,動態代理是多個代理功能對應一個代理類。下面是生成http請求的動態代理類,Proxy.newProxyInstance()中通過介面生成動態代理類,newProxyInstance()方法中先對interfaces介面做拷貝,再根據拷貝的介面和類載入器生成代理類,最後獲取代理類的構造方法,再返回由構造方法例項化的代理物件。在InvocationHandler回撥的invoke方法中實現http請求邏輯,具體的實現方式交給ServiceMethod。

 public <T> T create(Class<T> service){
 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ServiceMethod serviceMethod = loadServiceMethod(method);
        return serviceMethod.invoke(args);
       }
     });
   }
@CallerSensitive
   public static Object newProxyInstance(ClassLoader loader,
                      Class<?>[] interfaces,
                      InvocationHandler h)
     throws IllegalArgumentException
   {
     Objects.requireNonNull(h);
​
        //對interfaces介面做拷貝
     final Class<?>[] intfs = interfaces.clone();
    
     // Android-removed: SecurityManager calls
     /*
     final SecurityManager sm = System.getSecurityManager();
     if (sm != null) {
       checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
     }
     */
​
     /*
     * Look up or generate the designated proxy class.
     */
     //根據拷貝的介面和類載入器生成代理類
     Class<?> cl = getProxyClass0(loader, intfs);
​
     /*
     * Invoke its constructor with the designated invocation handler.
     */
     try {
       // Android-removed: SecurityManager / permission checks.
       /*
       if (sm != null) {
         checkNewProxyPermission(Reflection.getCallerClass(), cl);
       }
       */
​
            //獲取代理類的構造方法
       final Constructor<?> cons = cl.getConstructor(constructorParams);
       final InvocationHandler ih = h;
       if (!Modifier.isPublic(cl.getModifiers())) {
         // BEGIN Android-changed: Excluded AccessController.doPrivileged call.
         /*
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
           public Void run() {
             cons.setAccessible(true);
             return null;
           }
         });
         */
​
         cons.setAccessible(true);
         // END Android-removed: Excluded AccessController.doPrivileged call.
       }
       //返回由構造方法例項化的代理物件
       return cons.newInstance(new Object[]{h});
     } catch (IllegalAccessException|InstantiationException e) {
       throw new InternalError(e.toString(), e);
     } catch (InvocationTargetException e) {
       Throwable t = e.getCause();
       if (t instanceof RuntimeException) {
         throw (RuntimeException) t;
       } else {
         throw new InternalError(t.toString(), t);
       }
     } catch (NoSuchMethodException e) {
       throw new InternalError(e.toString(), e);
     }
   }

實現Retrofit第三步

在第二步利用動態代理獲取代理物件的create方法回撥中的invoke方法中實現http請求,這一步講講ServiceMethod如何實現http請求;

ServiceMethod要根據create傳入的api請求介面

public interface Apitest1 {
  @POST("/v3/weather/weatherInfo")
  Call postTest1(@Field("city") String city, @Field("key") String key);
​
  @GET("/v3/weather/weatherInfo")
  Call getTest1(@Query("city") String city, @Query("key") String key);
}

通過反射獲取Apitest1介面中宣告方法的註解和方法引數上的註解獲得請求方式,請求url,請求引數等,利用OkHttp傳送這次請求。

ServiceMethod類的物件也是通過構建者模式建立起來的,在ServiceMethod類中定義內部類Builder。

定義Builder的構造方法,傳參Method和MyRetrofit 在構造方法中做兩件事情

第一 ,通過反射method.getDeclaredAnnotations()獲取方法上的註解,得到請求方式(post or get),請求url。

第二,通過method.getParameterAnnotations()獲得方法引數的註解,得到請求引數(這裡的請求引數是 @Query("city")中的city),然後根據不同註解型別將獲取的註解值放入不同的ParamHandler中,Field型別放FieldParamHandler,Query型別放QueryParamHandler中。

最後build()方法返回ServiceMethod例項。

在invoke方法中傳入引數為Apitest1宣告的函式中的引數,再將引數和ParamHandler陣列構建成請求體formBody,最後由url,formBody和請求方式建立request請求,最後用OKhttp框架中factory.newCall(request)執行請求。


public class ServiceMethod {
   private static HttpUrl.Builder formBuilder;
   private static FormBody.Builder formBodyBuilder;
   private Call.Factory factory;
   private HttpUrl baseUrl;
   private String relativeUrl;
   private Boolean hasBody;
   private String httpMethod;
   private ParamHandler[] paramHandlers;
​
   public ServiceMethod(Builder builder){
     this.factory = builder.factory;
     this.baseUrl = builder.baseUrl;
     this.relativeUrl = builder.relativeUrl;
     this.hasBody = builder.hasBody;
     this.httpMethod = builder.httpMethod;
     this.paramHandlers = builder.methodParamHandler;
   }
​
   public Object invoke(Object[] args) {
     for (int i = 0; i < paramHandlers.length; i++) {
       paramHandlers[i].apply(this, (String) args[i]);
     }
     if(formBuilder == null){
       formBuilder = baseUrl.newBuilder(relativeUrl);
     }
     HttpUrl url = formBuilder.build();
     if(formBodyBuilder == null){
       formBodyBuilder = new FormBody.Builder();
     }
     FormBody formBody = null;
     if(hasBody){
       formBody = formBodyBuilder.build();
     }
     Request request = new Request.Builder().url(url).method(httpMethod,formBody).build();
     return factory.newCall(request);
   }
​
   public static void addParamToFormBody(String key,String value){
     if(formBodyBuilder == null){
       formBodyBuilder = new FormBody.Builder();
     }
     formBodyBuilder.add(key,value);
   }
​
   public void addParamToQueryFormBody(String key, String value){
     if(formBuilder == null){
       formBuilder = baseUrl.newBuilder(relativeUrl);
     }
     formBuilder.addQueryParameter(key,value);
   }
​
   public static class Builder{
     private  ParamHandler[] methodParamHandler;
     private Annotation[] methodOverAnnotations;
     private Annotation[][] methodAnnotations;
     private Call.Factory factory;
     private HttpUrl baseUrl;
     private String relativeUrl;
     private Boolean hasBody;
     private String httpMethod;
     public Builder(Method method,MyRetrofit myRetrofit){
       this.methodOverAnnotations = method.getDeclaredAnnotations();
       this.methodAnnotations = method.getParameterAnnotations();
       this.factory = myRetrofit.factory;
       this.baseUrl = myRetrofit.baseUrl;
       for (Annotation methodOverAnnotation : methodOverAnnotations) {
         if(methodOverAnnotation instanceof POST){
           this.hasBody = true;
           this.httpMethod = "POST";
           this.relativeUrl = ((POST) methodOverAnnotation).value();
         }else if(methodOverAnnotation instanceof GET){
           this.httpMethod = "GET";
           this.hasBody = false;
           this.relativeUrl = ((GET) methodOverAnnotation).value();
         }
​
       }
       int length = methodAnnotations.length;
       methodParamHandler = new ParamHandler[length];
       for (int i = 0; i < length; i++) {
         Annotation[] annotations = methodAnnotations[i];
         for (Annotation annotation : annotations) {
           if(annotation instanceof Field){
             methodParamHandler[i] = new ParamHandler.FieldParamHandler(((Field) annotation).value());
           } else if(annotation instanceof Query){
             methodParamHandler[i] = new ParamHandler.QueryParamHandler(((Query) annotation).value());
           }
         }
       }
     }
​
     public ServiceMethod build(){
       return new ServiceMethod(this);
     }
​
   }
}
​