Retrofit2基础使用与解析:从使用步骤深入分析源码

Android 网络请求库Retrofit使用详解 1、首先在Android项目中引入需要的依赖。2、创建一个单例类,返回Retrofit对象。 阅读详情

使用步骤

步骤一 添加依赖、权限

dependencies {
    compile 'com.squareup.retrofit2:retrofit:2.0.2'
    // Retrofit库
    compile 'com.squareup.okhttp3:okhttp:3.1.2'
    // Okhttp库
  }

联网权限:

<uses-permission android:name="android.permission.INTERNET"/>

步骤二 创建接收数据实体类

public class Reception {
    ...
        }

依据服务器返回的数据,建造实体类承载数据

步骤三 创建网络请求接口

public interface GetRequest_Interface {
    @GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
    Call<Translation>  接口方法();
}

使用注解进行请求方式、参数的设置。
方法的返回值默认使用Call<数据实体类>。(使用RxJava时用Observable<实体类>)

步骤四 创建Retrofit实例

 Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://fanyi.youdao.com/") // 网络请求基础Url地址
                .addConverterFactory(GsonConverterFactory.create()) // 数据解析器
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 网络请求适配器
                .build();

步骤五 创建网络请求接口实例

// 创建 网络请求接口 的实例
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);

//对 发送请求 进行封装
Call<Reception> call = request.接口方法名();

调用retrofit.create方法获取请求接口的实体类,调用该实体类方法即可对请求进行封装。

步骤六 发出网络请求

//发送网络请求(异步)
call.enqueue(new Callback<Translation>() {
    //请求成功时回调
    @Override
    public void onResponse(Call<Translation> call, Response<Translation> response) {
        //请求处理,输出结果
        response.body().show();
    }

    //请求失败时候的回调
    @Override
    public void onFailure(Call<Translation> call, Throwable throwable) {
        System.out.println("连接失败");
    }
});

// 发送网络请求(同步)
Response<Reception> response = call.execute();

使用生成的call,分别调用enqueue、execute进行异步、同步请求。

步骤七 处理返回的数据

response.body().show();

使用数据response进行数据处理。

逐步骤进行源码分析

步骤四 创建retrofit实例

 Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://xxx.xxx.xxx/") // 网络请求基础Url地址
                .addConverterFactory(GsonConverterFactory.create()) // 数据解析器
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 网络请求适配器
                .build();

可以看出实例是使用建造者模式创建的,由用户传入一些基础设置参数后,即可build目标实例

new Retrofit:Retrofit类

深入Retrofit类内部看它的成员,分析作用。

public final class 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;
  }

Map<Method, ServiceMethod<?, ?>> serviceMethodCache:用于存储ServiceMethod,即依据接口生成的网络请求方法。(此处与学习的博客用的数据博客发生变化,我的版本用ConcurrentHashMap,而参考博客版本用的LinkedHashMap)
okhttp3.Call.Factory callFactory:生成网络请求器的工厂(生产Call)
HttpUrl baseUrl:网络请求的基础Url地址
List<Converter.Factory> converterFactories:数据转换器工厂集合(生产Converter)
List<CallAdapter.Factory> callAdapterFactories:网络请求适配器工厂集合(生产CallAdapter,用于将底层使用的OkHttpCall转换成适应于不同平台的网络请求器)
Executor callbackExecutor:回调方法执行器
boolean validateEagerly:标记是否需要提前对接口注解进行验证转换
此处多次使用工厂模式,工厂模式可以自动生成对应对象(产品),用户无需再关心生成过程,可以将心思放到流程开发上。

new Retrofit.Builder():Builder类

成员

 public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;
    }

Builder类的成员和Retrofit类是对应的,多了一个platform成员

实例化过程
第一步调用无参构造,内部又调用Builder(Platform platform)有参构造实现

public Builder() {
  this(Platform.get());
}

深入Platform类:

private static final Platform PLATFORM = findPlatform();

static Platform get() {
  return PLATFORM;
}

使用单例模式进行参数获取。

private static Platform findPlatform() {
  try {
    Class.forName("android.os.Build");
    if (Build.VERSION.SDK_INT != 0) {
      return new Android();
    }
  } catch (ClassNotFoundException ignored) {
  }
  try {
    Class.forName("java.util.Optional");
    return new Java8();
  } catch (ClassNotFoundException ignored) {
  }
  return new Platform();
}

借助Java反射完成对当前平台的识别,提供不同的实例,安卓使用返回new Android()

继续深入Android类

  static class Android extends Platform 

该类是Platform的内部类

    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

设置默认的回调方法执行器,主要用于在主、子线程切换,将请求数据返回到主UI线程进行方法回调

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

该默认执行器保存主线程的handler,使用post方法切换到主线程进行回调

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

创建默认网络请求适配器,所需执行器参数,以便后续请求完成后,在对应执行器上回调。

上述流程主要是依据安卓平台进行线程切换以完成子青丘县城完成后到主UI线程的回调。(切换是先由ExecutorCallAdapterFactory获取请求器Call,调用该Call的请求方法内部调用了传入的执行器Executor的回调execute方法)

到此处platform获取完成,再看调用的Builder有参构造方法:

Builder(Platform platform) {
  this.platform = platform;
}

将获取的参数设置到Builder内。
至此Builder初始化完成,其内部配置了默认Android平台数据、默认网络请求适配器工厂defaultCallAdapterFactory(用于将默认Call再次封装)、给converterFactories和callAdapterFactories创建容器。

.baseUrl(“”)
public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      HttpUrl httpUrl = HttpUrl.parse(baseUrl);
      if (httpUrl == null) {
        throw new IllegalArgumentException("Illegal URL: " + baseUrl);
      }
      return baseUrl(httpUrl);
    }

第一步将字符串参数转换为适合OkHttp的Url格式,将该Url传入下一函数:

public Builder baseUrl(HttpUrl baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }

这一层将Url分段,判断是否以/结尾,若数据合理则记录到Builder的baseUrl成员内。
该方法流程就是将字符串网址转换为合适格式后,进行数据合理判断,再存储起来。

.addConverterFactory(GsonConverterFactory.create())

GsonConverterFactory.create()
Gson数据转换器工厂创建:

  public static GsonConverterFactory create() {
    return create(new Gson());
  }

外部调用无参函数,内部传入Gson实例

  public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
  }

此处依据使用的Gson实例真正返回工厂实例

  private GsonConverterFactory(Gson gson) {
    this.gson = gson;
  }

构造方法就是将Gson对象保存起来

addConverterFactory()

    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

将创建的工厂存储到Builder的转换器工厂集合中
剩余工厂参数配置流程基本同此。

.build()
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

baseUrl必须配置好

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

判断是否设置过网络请求执行器工厂,若没设置,采用默认OkHttp进行网络请求

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

判断是否设置过回调执行器,若没设置,采用默认安卓自身的执行器(在platform中实现)

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

依旧是接收所有配置进来的转换器工厂,先加入系统默认数据转换器BuiltInConverters,再加入配置好的工厂
上述两个列表存储,后续查找使用都是从头遍历找到尾,固越在前面优先级越高。

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

最后调用Retrofit的构造函数生成实例。(unmodifiableList会使列表数据可以读取,但不能修改)

步骤五 创建网络请求接口实例

GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);

Call<Reception> call = request.接口方法名();
retrofit.create()
public<T> T create(final Class<T> service) {

依据传入的接口class对象创建

  Utils.validateServiceInterface(service);

此处判断是否是有效接口 方法一

  if (validateEagerly) {
    eagerlyValidateMethods(service);
  }

依据先前提到的boolean对象,判断是否需要提前验证 方法二
上述代码中详细方法解析:
方法一

  static <T> void validateServiceInterface(Class<T> service) {
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }
    if (service.getInterfaces().length > 0) {
      throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
    }
  }

判断有效①class对象必须是接口②不可实现多个接口

方法二

private void eagerlyValidateMethods(Class<?> service) {
  Platform platform = Platform.get();
  for (Method method : service.getDeclaredMethods()) {
    if (!platform.isDefaultMethod(method)) {
      loadServiceMethod(method);
    }
  }
}

将接口中非系统默认方法加载起来

接下来是重点代理模式的实现

  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 (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
          if (platform.isDefaultMethod(method)) {
            return platform.invokeDefaultMethod(method, service, proxy, args);
          }

上述是将java、系统默认的方法不需记录直接通过反射调用即可。

          ServiceMethod<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);
          OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.adapt(okHttpCall);
        }
      });
}

以上三步是生成服务最重要的部分

ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);

依据接口种方法的注解生成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 = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

从方法缓存中查找是否加载过相同方法,若没有则采用建造者模式新生成(单例模式)

result = new ServiceMethod.Builder<>(this, method).build();

new ServiceMethod类

final class ServiceMethod<R, T> {
  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);
  //使用正则判断接口名称、URL是否合法

  private final okhttp3.Call.Factory callFactory;		//网络请求工厂
  private final CallAdapter<R, T> callAdapter;			//请求适配器

  private final HttpUrl baseUrl;						//网络请求基础URL地址
  private final Converter<ResponseBody, R> responseConverter;	//数据转换器
  private final String httpMethod;						//网络请求的HTTP方法(GET、POST...)
  private final String relativeUrl;						//网络请求相对地址
  private final Headers headers;						//网络请求中http请求头,键值对设置参数
  private final MediaType contentType;					//网络http请求报文body类型
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  //依据注解设置参数
  private final ParameterHandler<?>[] parameterHandlers;//方法参数处理器,解析API定义时的方法参数,在请求时进行设置
  }

该类包含了发出具体网络请求需要的全部内容

.Builder<>(this, method)
Builder类的构造方法:

    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

依据传入方法获取其注解、参数类型、参数注解等内容

.build()

public ServiceMethod build() {
  callAdapter = createCallAdapter();
  responseType = callAdapter.responseType();

此处获取网络请求适配器 方法一
并且依据适配器获取合适的返回值类型

  if (responseType == Response.class || responseType == okhttp3.Response.class) {
    throw methodError("'"
        + Utils.getRawType(responseType).getName()
        + "' is not a valid response body type. Did you mean ResponseBody?");
  }

判断获取的返回值类型是否合理

  responseConverter = createResponseConverter();

创建数据转换器 方法二

  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }
  if (httpMethod == null) {
    throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
  }

遍历方法注解并且进行解析并将其设置入httpMethod(主要获取HTTP网络请求方式,用String保存如GET等)

  int parameterCount = parameterAnnotationsArray.length;
  parameterHandlers = new ParameterHandler<?>[parameterCount];
  for (int p = 0; p < parameterCount; p++) {
    Type parameterType = parameterTypes[p];
    if (Utils.hasUnresolvableType(parameterType)) {
      throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
          parameterType);
    }

    Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
    if (parameterAnnotations == null) {
      throw parameterError(p, "No Retrofit annotation found.");
    }

    parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
  }

对参数逐个依据注解、类型进行解析,生成handler

  return new ServiceMethod<>(this);
}

最后将该方法配置完成即可返回此对象。

方法一 createCallAdapter()

private CallAdapter<T, R> createCallAdapter() {
  Type returnType = method.getGenericReturnType();
  Annotation[] annotations = method.getAnnotations();
  try {
    return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
  } catch (RuntimeException e) {
    throw methodError(e, "Unable to create call adapter for %s", returnType);
  }
}

读取方法的返回值类型、方法注解生成适配器,该适配器工厂的选取在创建Retrofit实例时用列表存储,此处从前向后挨个使用即可。

方法二 createResponseConverter()

    private Converter<ResponseBody, T> createResponseConverter() {
      Annotation[] annotations = method.getAnnotations();
      try {
        return retrofit.responseBodyConverter(responseType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create converter for %s", responseType);
      }
    }

原理同方法一获取适配器的过程,依据方法注解,在Retrofit实例的转换器工厂列表选取合适工厂进行生产

至此一个方法解析就完成了,后续在接口代理中将该方法对象加入缓存即可。

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

new OkHttpCall<>类

final class OkHttpCall<T> implements Call<T> {
  private final ServiceMethod<T, ?> serviceMethod;		//该网络请求方法对象,保存所有参数内容等
  private final @Nullable Object[] args;				//网络请求接口的参数

  private volatile boolean canceled;

  private @Nullable okhttp3.Call rawCall;				//最终实际进行网络请求的类
  private @Nullable Throwable creationFailure;
  private boolean executed;
  }

这一步就是将获取好的方法、传入的参数封装入Call,以便后续请求时直接调用获取

return serviceMethod.adapt(okHttpCall);

最后一步使用适配器将请求器转换为合适版本,此处使用不同适配器是属于装饰模式,内部仍然使用okHttpCall执行网络请求,但在其之上还要有其他操作就依据使用的适配器进行装饰。
至此,retrofit.create就分析完成,即完成了对网络请求接口的配置

Call call = request.接口方法名();

从依据接口生成的request中获取用于网络请求的执行器Call,此处的接口方法会被之前动态代理的invoke拦截,执行其中的内容(即将接口方法进行解析配置)

步骤六 发出网络请求

从基础的OkHttpCall的execute同步请求方法出发:

@Overridepublic Response<T> execute() throws IOException {
  okhttp3.Call call;

  synchronized (this) {
    call = rawCall;
    if (call == null) {
      try {
        call = rawCall = createRawCall();
      } catch (IOException | RuntimeException | Error e) {
        throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
        creationFailure = e;
        throw e;
      }
    }
  }

  return parseResponse(call.execute());
}

首先这个Call的生成是在上一步调用方法时产生,看似调用了方法,实际被动态代理拦截,生成一个Call对象,内部包含了该方法的ServiceMethod对象和所需参数。
接着就是上述代码,首先查看Call是否内部Call是否生成,若没生成则同步锁生成一个createRawCall 方法一
最后使用生成的内部Call执行请求并且解析返回数据 方法二。

方法一 createRawCall()

  private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = serviceMethod.toCall(args);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

使用之前生成的serviceMethod(包含所有请求所需内容),依据传入参数生成发起请求使用的Call(生成了一个HTTP request)。

方法二 parseResponse(call.execute())
由生成的内部call(request)发起请求并且解析数据。

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
  ResponseBody rawBody = rawResponse.body();

  rawResponse = rawResponse.newBuilder()
      .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
      .build();

  int code = rawResponse.code();
  if (code < 200 || code >= 300) {
    try {
      ResponseBody bufferedBody = Utils.buffer(rawBody);
      return Response.error(bufferedBody, rawResponse);
    } finally {
      rawBody.close();
    }
  }

  if (code == 204 || code == 205) {
    rawBody.close();
    return Response.success(null, rawResponse);
  }

  ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
  try {
    T body = serviceMethod.toResponse(catchingBody);
    return Response.success(body, rawResponse);
  } catch (RuntimeException e) {
    catchingBody.throwIfCaught();
    throw e;
  }
}

数据处理首先对response进行解析
①状态码检查,依据不同状态码即可知道该请求的情况,进行相应处理
②当请求成功,会将body传入serviceMethod中,使用之前的设置好的数据转换器将其转换为所需数据类型,再调用Response.success,返回一个完整response

异步请求call.enqueue:

call.enqueue(new Callback<Translation>() {
    @Override
    public void onResponse(Call<Translation> call, Response<Translation> response) {
        response.body().show();
    }

    @Override
    public void onFailure(Call<Translation> call, Throwable throwable) {
        System.out.println("连接失败");
    }
});

请求的同步异步是相对于当前线程,并非任务的同步异步,进行同步请求通常将手动创建线程进行网络请求(否则将直接在主UI线程进行请求,阻塞),异步自动创建并执行,最后调回主线程进行数据处理。
异步请求采用静态代理模式,用户写好请求数据的处理后,等请求完成回到主线程直接进行方法回调。

@Override public void enqueue(final Callback<T> callback) {
  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()) {
            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进行的 分析一
callbackExecutor.execute()将最后的结果用执行器切换到主线程进行数据处理(安卓的默认执行器就是主线程执行器,是在先前platform中获取到的) 分析二

分析一 静态代理

  @Override public void enqueue(final Callback<T> callback) {
    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      @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) {
          t.printStackTrace();
        }
      }
    });
  }

先前静态代理执行的enqueue实际还是调用了OkHttpCall内部的enqueue(内部流程与同步相同,先查看内部call/request是否生成,生产call并进行调用),在okhttp基础上以静态代理模式添加了线程切换操作。

至此整个流程全部完成。
后面的execute、enqueue都是解析的ExecutorCallbackCall,而不是OkHttpCall,因为在创建retrofit实例时,其中适配器的排序是将系统默认适配器排到了第一位,而安卓默认适配器就是ExecutorCallbackCallAdapter,所以一切业务层对call进行的调用都在对ExecutorCallbackCall的方法调用。

银河飞腾FT6678实战指南:OpenMP多核并行编程优化技巧 本文详细介绍了在银河飞腾FT6678多核处理器上使用OpenMP进行并行编程的实战技巧与优化方法。从基础语法到环境配置,再到性能优化的五大核心技巧,包括循环并行化、并行粒度控制、reduction子句使用等,帮助开发者充分发挥FT6678的8核计算能力。通过实际案例展示如何将图像处理算法从200ms优化到28ms,并深入探讨了任务调度、内存访问优化等进阶主题。 阅读详情

相关推荐

H无穷控制学习笔记——加权灵敏度H无穷控制问题

一、加权灵敏度H无穷问题 系统结构如上图所示。被控对象P的状态空间方程为(Ap,Bp,Cp,DpA_p,B_p,C_p,D_pAp​,Bp​,Cp​,Dp​),加权函数W1的状态空间方程为(A1,B1,C1,D1A_1,B_1,C_1,D_1A1​,B1​,C1​,D1​),加权函数W2的状态空间方程为(A2,B2,C2,D2A_2,B_2,C_2,D_2A2​,B2​,C2​,D2​),加权函数W3的状态空间方程为(A3,B3,C3,D3A_3,B_3,C_3,D_3A3​,B3​,C3​,D3​)。

一饮丶一啄的博客 4349

Retrofit2 详解和使用(一)

前言:要么出击,要么出局,命运女神总会眷顾拼尽全力的一方。 一、概述 1、什么是retrofit retrofit是现在比较流行的网络请求框架,可以理解为okhttp的加强版,底层封装了Okhttp。准确来说,Retrofit是一个RESTful的http网络请求框架的封装。因为网络请求工作本质上是由okhttp来完成,而Retrofit负责网络请求接口的封装。 本质过...

https://juejin.cn/user/1654096907477549/posts 7万+

解决Word中英文混排的5个常见排版问题(含单词换行、间距调整等)

本文详细解析Word中英文混排的5大常见排版问题,包括单词换行、间距调整、标点混用等,提供专业解决方案。通过设置段落格式、调整兼容性选项和使用字体组合等技巧,帮助用户轻松解决文档排版难题,提升专业性和阅读体验。

vim8coder的博客 1332

Retrofit2讲解

Retrofit2学习分析详解,附接口,附遇见问题分析

qq_52332769的博客 7132

解密TMS320F28377D双核工程中的内存分配艺术:从CMD文件到实战优化

本文深入解析TMS320F28377D双核DSP的内存管理艺术,从CMD文件配置到实战优化技巧。详细介绍了SARAM、GSRAM等内存类型的特性与配置方法,提供双核协同、性能优化及高级调试的实用方案,帮助开发者提升系统实时性和稳定性。

weixin_29190651的博客 662

实战指南:基于华为Ascend NPU的大模型W8A8量化调优与精度提升

本文提供了一份基于华为Ascend NPU进行大模型W8A8量化的实战调优指南。详细介绍了从环境搭建、使用msmodelslim框架进行基础量化,到通过离群值抑制、校准集优化和量化回退等关键技术提升精度的全流程。旨在帮助开发者在华为NPU硬件上实现模型推理的显著加速,同时有效控制精度损失。

weixin_29227425的博客 271

详细的 Retrofit 2.0 使用教程

这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)前言在Andrroid开发中,网络请求十分常用而在Android网络请求库中,Retrofit是当下最热的一个网络请求库今天,我将献上一份非常详细Retrofit v2.0的使用教程,希望你们会喜欢。如果对Retrofit v2.0的源码感兴趣,可看文章:Android:手把手带你深入剖析 Retrofit 2.0 源码目录1. 简...

daimengs的博客 2008

UMI——斯坦福刷盘机器人:通过手持夹爪革新数据收集方式,且使用视觉SLAM和Diffusion Policy预测动作

没想到今年年初的斯坦福mobilealoha的热度刚过,而到今年2月的下旬,斯坦福另一个团队又推出了UMI刷盘机器人,且这两个团队还互相认识、还在一块共同切磋(顺带小小感叹一下,斯坦福的氛围是真好而且真高产)斯坦福UMI刷盘机器人其与mobile aloha(以及AirExo: Low-Cost Exoskeletons for Learning Whole-Arm Manipulation in the Wild)最大的不同在于其收集数据处理的非真实的机器人,而是一个手持夹持器(从而大幅降低成本)

u013250861的博客 1357

Carson带你学Android:这是一份详细的 Retrofit使用教程(含实例讲解)

前言 在Andrroid开发中,网络请求十分常用 而在Android网络请求库中,Retrofit是当下最热的一个网络请求库 今天,我将献上一份非常详细Retrofit v2.0的使用教程,希望你们会喜欢。 如果对Retrofit v2.0的源码感兴趣,可看文章:Android:手把手带你深入剖析 Retrofit 2.0 源码 目录![目录](http://upload-

Carson带你学Android 25万+

YOLOv11 改进 - 注意力机制 | LS-YOLO MSFE 多尺度特征提取模块:并行分支结构增强多尺度感知,优化遥感与小目标检测

本文介绍了一种用于滑坡检测的模型LS-YOLO及其在YOLOv11中的结合应用。LS-YOLO首先构建多尺度滑坡数据集MSLD,为模型训练提供丰富数据。设计了基于高效通道注意力、平均池化和空间可分离卷积的多尺度特征提取模块MSFE,充分提取滑坡特征信息。在解耦头中采用膨胀卷积增加模型感受野。我们将MSFE模块集成进YOLOv11,替换部分原有模块。实验表明,改进后的YOLOv11在数据集中表现出色 。

魔改工程师的博客 870

云端办公文件存储与访问全攻略:选型、预算、实操一本通

随着远程办公、多设备协作成为常态,“文件云端存储、随时调用” 已成为提升办公效率的核心需求。本文从用户实际场景出发,系统拆解云端存储的选型逻辑、全场景费用预算,重点解答 “文件能否直接在线打开” 的核心疑问,并提供实操技巧与安全保障方案,覆盖个人、小团队(含兼职)、企业全维度需求,帮助不同规模用户快速搭建高效、低成本的云端办公体系。

hy行者勇哥的博客 1240

关于Retrofit2.0源码的学习和理解

今年4月初,刚接触到RxJava、Retrofit等框架的时候,当时也是一头楞,因为我以前的项目中都是采用MVP加上Volley请求框架的结构。使用Retrofit开源框架搭建项目这个在网络上已经有很多很好的介绍了,在这里就不去探讨怎么使用。之所以要去写源码的实现,一方面呢是因为最近研读了下,对Retrofit有了一些了解,主要是另一个方面,写一写博客(当写笔记吧),一来理清下思路,二来相当于做个

zoujian的博客 1603

SAM3 几行代码支持任意图像分辨率,减少显存占用(针对transformers库)

几行代码让sam3支持任意图像分辨率

qq_41234663的博客 156

Retrofit2源码分析

Retrofit2源码分析 本文只在重点分析retrofit2源码,对于详细使用方法请参考官网即可;本文的分析思路是框架怎么构造请求到发送请求,再到解析数据更新给UI层; 依赖引用: implementation 'com.squareup.retrofit2:retrofit:2.0.2' implementation 'com.squareup.retrofit2:converter-...

mori2014的专栏 235

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Retrofit_2.5.0源码分析

Retrofit_2.5.0源码分析 基于Retrofit:3.12.0:https://github.com/square/retrofit/tree/parent-2.5.0 RTFSC Read The Fucking Source Code 流程分析 用户层面调用形式: @NonNull protected Retrofit.Builder createBuilder() {...

高远的博客 505

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

【Android源码解析】一篇搞定“路由、网络层、UI层、通信层

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!资料⬅专栏获取。

asdzxc324as的博客 1012

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Retrofit2.9.0版本主流程分析

简介 Retrofit turns your HTTP API into a Java interface. Retrofit将HTTP API转换为Java接口 本文基于Retrofit2.9.0版本源码分析! 依赖添加: com.squareup.retrofit2:retrofit:2.9.0 使用 我们在这以官网的Demo为例,来看下最简单的使用: public interface GitHubService { @GET("users/{user}/repos") Call<List

datian1234的博客 1018

Retrofit源码解析

动态代理拦截方法调用。RequestFactory 解析方法注解和参数,生成请求模板。OkHttpCall 使用请求模板和参数构造 OkHttp 的 Request实例。OkHttp 发送请求,获取响应。Converter 将 ResponseBody 转换为目标数据类型。CallAdapter 将 Call 适配为 Observable 等其他类型。根据配置切换线程到主线程更新 UI。

u010131088的博客 852

Android 网络框架之Retrofit源码解析

代码真的是重质不重量,质量高的代码,是当前代码界提倡的,当然写出高质量的代码肯定需要一个相当高的专业素养,这需要在日常的代码书写中逐渐去吸收掌握,谁不是每天都在学习呀,目的还不是为了一个,为实现某个功能写出高质量的代码。所以,长征路还长,大家还是好好地做个务实的程序员吧。最后,小编这里有一系列Android提升学习资料,有兴趣的小伙伴们可以来看下哦~《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可免费领取!

2301_82242251的博客 801

展开说说Android之Retrofit详解_源码解析

本文主要从六个方面分析了Retrofit源码实现:首先介绍了Retrofit的核心类和接口,包括Retrofit类、ServiceMethod类等;接着解析了@GET、@POST等注解的作用;然后通过OkHttpCall类揭示了Retrofit封装OkHttp的实现;解释了Retrofit异步请求能在主线程返回的原理;梳理了请求的完整流程;最后总结了Retrofit的优缺点。文章详细呈现了Retrofit从注解解析到最终请求实现的完整机制,特别是通过动态代理和线程切换的实现细节

Hidanchaofan的博客 1034

Retrofit源码全方面解析

如今作为一个Android开发者,网络请求这块离不开square公司的全家桶,今天我们就来分析一下其中的Retrofit框架的源码。 为什么使用Retrofit 因为方便、直观,和OkHttp的结合天衣无缝: @GET("weather") fun weather(@Query("latitude") latitude: String, @Query("longitude") longitude: String): Flowable<String> 通过注解,对于这样的一个GET请求,请求参数

xlh1191860939的博客 2490

Android-retrofit源码解析

retrofit是目前比较流行的网络框架,但它本身并没有网络请求的功能,网络请求的功能是由okhttp来完成的。retrofit只是负责网络请求接口的封装,让我们更加方便的请求网络。在对retrofit框架进行了解之前,我们需要先了解okhttp,另外retrofit涉及到的设计模式很多,我们主要要了解动态代理模式和适配器模式。Android-okhttp详解-优快云博客Java 代理模式之静态代理与动态代理_java静态代理模式-优快云博客。

袁震的博客 1287

Retrofit源码分析及理解

Retrofit内部有着简捷、优雅的结构设计。当然对于新手来说,Retrofit也有着不宜理解和上手的问题。不过瑕不掩瑜,Retrofit仍然是一款优秀的网络请求框架。 这边文章除了进行源码分析,还有个人对Retrofit的一些浅见和感悟。仅供读者参考。

阿根的专栏 1318

Retrofit2源码分析:架构全面解析

目录   一、概述 二、Retrofit2源码地址 三、Retrofit2简单使用 四、架构流程 1、流程图 2、流程讲解 五、源码分析 1、Retrofit的内部成员变量 2、Retrofit内部类Builder 3、创建Retrofit实例 4、Builder.build()方法 5、retrofit.create() 6、loadServiceMethod() ...

欢迎来到Cozing的博客 6020
上一篇: 安卓Room学习:数据库版本管理、数据迁移
下一篇: Android开源库:FileDownloader使用流程
魔幻音
博客等级 码龄6年 16粉丝 202原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔幻音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值