Marco de código abierto de Android: actualización

1 Breve descripción

Un cliente HTTP con seguridad de tipos para Android y Java.
Retrofit es un contenedor alrededor de un marco de solicitud web RESTful HTTP. Su capa inferior todavía se implementa en base a OkHttp, que es una mejora de OkHttp que se usa en Android.

// 这是一个例子
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("halloayu");

repos.enqueue(new Callback<List<Repo>>() {
    @Override
    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
        Log.e("Main", response.body().get(0).toString());
    }
    
    @Override
    public void onFailure(Call<List<Repo>> call, Throwable t) {
    }
});
复制代码

2 ¿Por qué existe un marco de Retrofit?

OkHttp es un marco de solicitud de red certificado oficialmente por Android, es muy poderoso, pero también tiene muchas deficiencias, como se muestra a continuación.

  1. OkHtt es muy tedioso para configurar solicitudes de red, especialmente cuando se configuran cuerpos de solicitud de red complejos, encabezados de solicitud y parámetros.
  2. El proceso de análisis de datos requiere que el usuario obtenga manualmente el ResponseBody para el análisis, que es difícil de reutilizar.
  3. El cambio de hilo no se puede hacer automáticamente.
  4. En caso de que tengamos solicitudes de red anidadas, caeremos en el "infierno de devolución de llamada".

Por lo tanto, para resolver estas deficiencias y hacer que las solicitudes de red sean fáciles de usar en el desarrollo de Android, nació el marco Retrofit, que esencialmente coloca una capa de "capa" en OkHttp, y las solicitudes internas aún se implementan en base a OkHttp.
Al mismo tiempo, Retrofit está diseñado para dos propósitos.

  • antes de la solicitud
    • Los encabezados de solicitud de red se pueden configurar de manera uniforme
    • Es muy conveniente reutilizar Solicitud, o crear una solicitud
  • después de la solicitud
    • El subproceso secundario debe cambiarse al subproceso de la interfaz de usuario para facilitar la actualización de la interfaz
    • Los datos devueltos se pueden analizar como Java Bean, que es conveniente de usar

3 Puntos principales del embalaje

Retrofit encapsula OkHttp principalmente en los siguientes puntos:

  1. El modo de construcción crea una configuración básica para las solicitudes de red.
  2. Combinación de solicitudes de red HTTP con clases anotadas
  3. Proporciona los datos Gsondevueltos por el análisis .json
  4. El ejecutor completa el cambio de hilo

El núcleo de la implementación de su solicitud radica en la "anotación", el "proxy dinámico" y la "reflexión".

4 notas

Http tiene 8 solicitudes de red: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, HTTP

Retrofit implementa este tipo de solicitudes a través de una combinación de más de 20 anotaciones.企业微信截图_bbd04297-5bd9-4f56-910b-8d60d495ecb3.png

5 proxies dinámicos

熟悉设计模式的都知道,代理模式的思想是通过一个“代理商”,让”用户“通过它处理难以处理的”事情“。
在最上面Retrofit的使用例子中,先是通过建造者模式创建了一个retrofit实例,然后走GitHubService service = retrofit.create(GitHubService.class),这里面就是一个动态代码,我们来具体看看做了什么。

public <T> T create(final Class<T> service) {
    // 验证接口
    validateServiceInterface(service);
    // 动态代理
    return (T)
        Proxy.newProxyInstance(
        service.getClassLoader(),
        new Class<?>[] {service},
        new InvocationHandler() {
            private final Platform platform = Platform.get();
            private final Object[] emptyArgs = new Object[0];
            
            @Override
            public @Nullable 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);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
            }
        });
}
复制代码

从代码中我们可以看出,它代理了传入接口类中的所有接口方法,当我们调,service.listRepos("halloayu"),就会走InvocationHandler中的invoke方法。

// 从缓存中拿,没拿到,ServiceMethod进行处理
ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;
    
    synchronized (serviceMethodCache) {
        result = serviceMethodCache.get(method);
        if (result == null) {
            result = ServiceMethod.parseAnnotations(this, method);
            serviceMethodCache.put(method, result);
        }
    }
    return result;
}
复制代码

ServiceMethod就像是一个中央处理器,传入Retrofit对象和Method对象,调用各个接口和解析器,最终生成一个Request,包含api 的域名、path、http请求方法、请求头、是否有body、是否是multipart等等。最后返回一个Call对象,Call接口的默认实现是OkHttpCall,它默认使用OkHttp3作为底层http请求client。

@Override
final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    // 使用适配器去转换返回数据
    return adapt(call, args);
}
复制代码

使用Java动态代理的目的就要拦截被调用的Java方法,然后解析这个Java方法的注解,最后生成Request由OkHttp发送。

// 异步请求源码
@Override
public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");
    
    ...
    
    call.enqueue(
        new okhttp3.Callback() {
            @Override
            public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
                Response<T> response;
                try {
                    // 解析返回数据,里面用我们配置的GSON解析
                    response = parseResponse(rawResponse);
                } catch (Throwable e) {
                    throwIfFatal(e);
                    callFailure(e);
                    return;
                }
                
                try {
                    // 先走我们定义适配器转换数据,然后走自定义callback
                    callback.onResponse(OkHttpCall.this, response);
                } catch (Throwable t) {
                    throwIfFatal(t);
                    t.printStackTrace(); // TODO this is not great
                }
            }
            
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                callFailure(e);
            }
            
            private void callFailure(Throwable e) {
                try {
                    callback.onFailure(OkHttpCall.this, e);
                } catch (Throwable t) {
                    throwIfFatal(t);
                    t.printStackTrace(); // TODO this is not great
                }
            }
        });
}
复制代码

6 线程切换

Retrofit实现子线程到主线程的切换也是基于Handler

static final class Android extends Platform {
    Android() {
        super(Build.VERSION.SDK_INT >= 24);
    }
    
    @Override
    public Executor defaultCallbackExecutor() {
        return new MainThreadExecutor();
    }
    
    @Nullable
    @Override
    Object invokeDefaultMethod(
        Method method, Class<?> declaringClass, Object object, Object... args) throws Throwable {
        if (Build.VERSION.SDK_INT < 26) {
            throw new UnsupportedOperationException(
                "Calling default methods on API 24 and 25 is not supported");
        }
        return super.invokeDefaultMethod(method, declaringClass, object, args);
    }
    
    static final class MainThreadExecutor implements Executor {
        // Handler
        private final Handler handler = new Handler(Looper.getMainLooper());
        
        @Override
        public void execute(Runnable r) {
            handler.post(r);
        }
    }
  }
复制代码

请求后,先走默认的线程切换适配器DefaultCallAdapterFactory,然后走自定义的callback。

@Override
public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");
    
    // 切换线程
    delegate.enqueue(
        new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
                callbackExecutor.execute(
                    () -> {
                        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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
        });
}
复制代码

7 总结

Retrofit的源码十分优秀,用注解的形式组合HTTP请求,通过代理接口,处理请求的逻辑,最后再执行请求。里面也大量使用反射,工厂方法,抽象接口来实现低耦合高扩展,非常值得一读的开源框架!

Supongo que te gusta

Origin juejin.im/post/7080366577379442719
Recomendado
Clasificación