Retrofit2.0源码解析

Retrofit 2.9.0 源码解析 Retrofit 2.9.0 1 Retrofit   1.1 retrofit介绍 A type-safe HTTP client for Android and Java. 一个安全类型的http请求的客户端。 底层网络请求是基于okhttp,retrofit对其进行了封装,提供了方便高效的网络访问框架   1.2 Retrofit 使用 1.2.1 简单使用 class RetrofitActivity : AppCompatActivity() { override fun onCreate 阅读详情

怎么使用就不详述了,我们主要来看原理。

  1. 得到retrofit对象
    我们首先通过建造者模式获得retrofit实例
    Builder(Platform platform) {
      this.platform = platform;
      // 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());
    }

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

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

    /** Add converter factory for serialization and deserialization of objects. */
    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }
 public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }
        /**
     * Add a call adapter factory for supporting service method return types other than {@link
     * Call}.
     */
    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      adapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }


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

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

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

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

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

在构造器中,首先获得当前设备的的平台信息,并把内置的BuiltInConverters添加到工厂集合,主要作用是使用多种converters时能够找到可以消耗该类型的转化器;
我们来看Platform这个类:

class 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) {
    }
    try {
      Class.forName("org.robovm.apple.foundation.NSObject");
      return new IOS();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

  Executor defaultCallbackExecutor() {
    return null;
  }

  CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
  }

  boolean isDefaultMethod(Method method) {
    return false;
  }

  Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, Object... args)
      throws Throwable {
    throw new UnsupportedOperationException();
  }

  @IgnoreJRERequirement // Only classloaded and used on Java 8.
  static class Java8 extends Platform {
    @Override boolean isDefaultMethod(Method method) {
      return method.isDefault();
    }

    @Override Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,
        Object... args) throws Throwable {
      // Because the service interface might not be public, we need to use a MethodHandle lookup
      // that ignores the visibility of the declaringClass.
      Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
      constructor.setAccessible(true);
      return constructor.newInstance(declaringClass, -1 /* trusted */)
          .unreflectSpecial(method, declaringClass)
          .bindTo(object)
          .invokeWithArguments(args);
    }
  }

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

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

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

  static class IOS extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private static Object queue;
      private static Method addOperation;

      static {
        try {
          // queue = NSOperationQueue.getMainQueue();
          Class<?> operationQueue = Class.forName("org.robovm.apple.foundation.NSOperationQueue");
          queue = operationQueue.getDeclaredMethod("getMainQueue").invoke(null);
          addOperation = operationQueue.getDeclaredMethod("addOperation", Runnable.class);
        } catch (Exception e) {
          throw new AssertionError(e);
        }
      }

      @Override public void execute(Runnable r) {
        try {
          // queue.addOperation(r);
          addOperation.invoke(queue, r);
        } catch (IllegalArgumentException | IllegalAccessException e) {
          throw new AssertionError(e);
        } catch (InvocationTargetException e) {
          Throwable cause = e.getCause();
          if (cause instanceof RuntimeException) {
            throw (RuntimeException) cause;
          } else if (cause instanceof Error) {
            throw (Error) cause;
          }
          throw new RuntimeException(cause);
        }
      }
    }
  }
}

我们可以看到,如果检测到Android平台,会首先创建一个默认MainThreadExecutor的方法,(会在retrofit的build方法中调用,然后加到adapterFactories中),它会获取ui线程的looper生成一个对应的handler,执行execute方法就是用主线程的handler执行handler.post(runnable)事件,然后用这个MainThreadExector生成一个默认的ExecutorCallAdapterFactory。Retrofit 需要 Java7 版本或 Android2.3 以上。

在build方法中我们可以看到必须传入baseurl,当不指定client的时候为默认的okhttpclient,在Platform中生成的MainThreadExecutor是回调执行者,在子线程获得网络数据之后转换到ui线程中,CallAdapterFactory通过工厂模式生成CallAdapter用静态代理的方式将网络请求返回的call进行包装,比如RxJava,ConverterFactory通过工厂模式生成Converter对网络请求数据进行转化,比如Gson。最后通过建造者模式生成retrofit对象 把定义的接口转化为实例

CallAdapter是Call的适配器,作用就是创建/转换Call对象,把Call转换成预期的格式。CallAdatper创建是通过CallAdapter.factory工厂类进行的,本身只有一个转换方法adapt()。创建CallAdatper Factory需要实现Factory接口,DefaultCallAdapter为Retrofit2自带默认Call转换器,用来生成OKHTTP的call请求调用。

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 {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

可以看出我们采用动态代理的方式,返回了我们传入的接口的代理实例,并和InvocationHandler关联起来,当我们调用代理类的方法时,invoke方法都会被执行,
invoke方法中首先把method转化为servicemethod

  ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

通过建造者模式将method构建为ServiceMethod,

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

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

      if (!hasBody) {
        if (isMultipart) {
          throw methodError(
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }

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

      if (relativeUrl == null && !gotUrl) {
        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError("Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError("Multipart method must contain at least one @Part.");
      }

      return new ServiceMethod<>(this);
    }

在build方法中,构建calladapter对象,

private CallAdapter<?> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
            "Method return type must not include a type variable or wildcard: %s", returnType);
      }
      if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
      }
      Annotation[] annotations = method.getAnnotations();
      try {
        return retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }

通过得到method的类型和注解,调用retrofit.callAdapter(returnType, annotations)——nextCallAdapter方法中会通过for循环从adapterFactories中获取calladAdapter对象,这会得到一个ExecutorCallAdapter对象;同理我们类似的得到responseConverter对象,主要是对数据进行转化。除此之外还会对方法注解进行解析

private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
        if (!Void.class.equals(responseType)) {
          throw methodError("HEAD method must use Void as response type.");
        }
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError("@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }

以及参数注解进行解析等。
得到ServiceMethod对象后,我们通过接口传入的参数来得到okhttpcall对象

OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

然后就是把okhttpcall封装为call对象serviceMethod.callAdapter.adapt(okHttpCall)serviceMethod.callAdapter就是之前提到的ExecutorCallAdapterFactory生成的CallAdapter,在它的adapt方法中

public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public <R> Call<R> adapt(Call<R> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

adapt方法会返回一个ExecutorCallBackCall对象,callbackExecutor就是我们在检测platform时创建的MainThreadExector,
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
,call是我们刚过传入的okhttpcall。
综上就是动态代理的作用,看上去是调用了接口的 方法,其实此时Retrofit把 接口翻译成一个HTTP请求,这个请求中有callAdapter,responseAdapter,okhttpcall三个重要的对象。我们得到接口的代理实例后,调用请求会触发InvocationHandler的invoke方法,并返回一个ExecutorCallBackCall对象,并把okhttpcall传入它的参数中,通过这个call对象完成我们的请求。有两种请求方式,execute和enqueue;

 异步请求enqueue中
static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");

      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()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

这里有两个对象,一个是callbackexecutor,一个是delegate,前者把网络线程切换到主线程中(我们在retrofit的build方法中检测platform时执行的),后者执行真正的网络请求(就是我们之前传入的callback对象)

@Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");

    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) {
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }

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

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

在okhttpcall的enque对象中我们直接调用的okhttp进行的网络异步操作;类似的okhttpcall也是应用okhttp进行的同步请求。关于okhttp在这里就不详述了,有兴趣的可以看下 深入解析OkHttp3

注意无论是同步操作还是异步操作每一个call对象实例只能被执行一次,多次执行抛出异常。并且我们通过Clone方法创建一个一模一样的实例,并且它的开销也是很小的。

下面是retrofit与另一款常用的volley库的简单对比:

Volley:
1.缓存处理;Volley自己就提供了一套完整的缓存处理方案,默认使用文件存储到磁盘中
2.代码简单,可读性高。
3.同一个请求如果同时都在发送,那么实际上只会有一个请求真正发出去, 其它的请求会等待这个结果回来
4.请求发送的时候提供了优先级的概念,但是是只保证顺序出去,不保证顺序回来
5.支持不同的Http客户端实现,默认提供了HttpClient和HttpUrlConnection的实现,而Retrofit在2.0版本之后,锁死在OkHttp上了。
6.支持请求取消
Retrofit:
1.较好的可扩展性,Volley中每一个新建一个Request时都需要指定一个父类,告知序列化数据的方式,而Retrofit中只需要在配置时,指定各种转换器即可。CallAdapter的存在,可以使你随意代理调用的Call
2.OkHttpClient自带并发光环,而Volley中的工作线程是自己维护的,那么就有可能存在线程由于异常退出之后,没有下一个工作线程补充的风险(线程池可以弥补这个缺陷),这在Retrofit中不存在
3.支持请求取消
4.Retrofit没有对缓存提供任何额外支持,缓存不在我们的控制范围之内,而是完全通过OkHttp来管理

Retrofit 最新源码解析 (附源码下载) 目录 1. 前言 2. 简介 3. 火热热的4个网络框架 4. 如何使用 5. 源码分析 6. 后记 1. 前言         今年是2020年了,也是我正式入驻优快云博客的第一年,说起来也凑巧,因为今年的黑天鹅事件导致我们不得不在家宅着,当然到2月中下旬很多企业都复工了,本人也一样进入了远程办公状态,其实本人挺懒的,写文章这种事情我其实是不怎么热衷的,主要还是因为在家宅久了觉得会不够充实,于是乎有时间去学习下当下流行的Android开发技术,想通过写博客的方式梳理下自己学到的知识点。好了,我就不废话了,直接进入真题吧,以下便是关于我学习Retrofit网络框架的总结。 2. 简介     立即下载

相关推荐

Zemax API 与 Python 的独立应用程序

Zemax 提供了多个 python 示例代码,位于 Documents\Zemax\ZOS-API Sample Code\Python。使用以下代码,它们保存在 ZOS 文件目录中:/Documents\Zemax\Samples\API\Python。此代码块定位已安装的 OpticStudio 版本,确定根目录,创建命名空间和类,加载局部变量。如果定义的镜头需要一些特殊的编辑,例如反转,一种快速方法是从位于编程选项卡的 ZOS-API 语法帮助中找到相应的命令。重新运行整个代码块,镜头方向会改变。

jkh920184196的博客 1977

Retrofit之CallAdapter简单解析

阅读本篇博客之前,建议读者先按顺序读一读博主的下面几篇博客: Retrofit源码解析之请求流程概述 Retrofit之Converter简单解析 Retrofit之OkhttpCall执行原理详解 根据前几篇博客我们知道,Retrofit常规使用方法可以用如下几行代码表示: MyApi api = retrofit.create(MyApi.class); /*获取Execut...

菜鸟博客 4544

STM32F103C8T6的PC13-15引脚配置避坑指南:为什么你的IO口不工作?

本文详细解析了STM32F103C8T6的PC13-15引脚作为普通IO口不工作的原因及解决方案。这三个引脚默认关联侵入检测和低速外部时钟等特殊功能,需先禁用TAMPER和LSE,并开启AFIO时钟,才能正确配置为普通GPIO。文章提供了标准外设库和HAL库的配置步骤、常见问题排查方法及硬件设计注意事项。

weixin_29169899的博客 522

面试官:关于 Retrofit 你知道多少?

);如果调用的是Object的方法,例如equalstoString,那就直接调用。如果是default方法(Java 8 引入),就调用default方法。

2401_84544780的博客 201

【AI智能体】图像处理-生成营销 Banner 图

生成营销 Banner 图是一款用于制作营销图片的智能体,它可以根据指定的营销活动内容,快速生成活动 Banner 图片,降低活动运营成本、提高制图效率。

AI创变工坊,和1000万新个体创业者一起成长!愿大家都能跟上时代的洪流,不被社会淘汰,愿大家的生活工作收入都能具备竞争力! 1175

GCdepth散点图绘制

基因组组装完成后,需要对组装结果进行评估,其中GC_depth图是一个比较重要的指标,改图的横坐标是GC含量,纵坐标是平均深度。以30k为窗口(window)无overlap计算其GC含量和平均深度。如果存在样品污染,通常能够从GC含量分析中呈现出来。下文探索了几种绘制GC_depth散点图的方法思路。

huangliangbo的专栏 8993

终极指南:如何使用Retrofit响应式适配器彻底告别回调地狱

Retrofit作为一款类型安全的HTTP客户端,广泛应用于Android和JVM平台。然而,传统的回调方式常常导致代码嵌套过深,形成"回调地狱"。本文将详细介绍如何通过Retrofit的响应式适配器,以更优雅的方式处理网络请求,让你的代码更加清晰易维护。 ## 什么是回调地狱?为什么需要响应式适配器? 在没有响应式适配器的情况下,使用Retrofit进行网络请求通常需要使用回调方式处理结果,

gitblog_00247的博客 902

从零开始理解固定翼能量控制:Pixhawk TECS算法保姆级教程

本文深入解析了Pixhawk飞控中的TECS(总能量控制)算法,旨在解决固定翼无人机纵向控制中速度与高度耦合的经典难题。教程从物理概念出发,阐释了TECS通过管理总能量与分配能量形态来实现油门与升降舵解耦的核心思想,并提供了参数调试的实战指南,帮助开发者优化飞行性能。

white的博客 249

Android Retrofit 源码分析

Retrofit 通过 java 接口以及注解来描述网络请求,并用动态代理的方式生成网络请求的 request,然后通过 client 调用相应的网络框架(默认 okhttp)去发起网络请求,并将返回的 response 通过 converterFactorty 转换成相应的数据 model,最后通过 calladapter 转换成其他数据方式(如 rxjava Observable等)。

sziitjin的博客 1327

基于VisionMaster的药丸外观缺陷机器视觉检测系统实战解析

机器视觉作为工业自动化的核心技术,通过图像采集与智能分析替代人眼,实现高精度、高效率的在线检测。其核心原理在于利用相机、镜头、光源等硬件获取目标图像,再通过图像处理算法提取特征并进行识别与判断。这项技术的核心价值在于能够大幅提升生产质量与效率,尤其在需要高速、高精度且重复性强的检测场景中优势显著。在制药、食品、电子等行业的表面缺陷检测、尺寸测量、字符识别等环节应用广泛。本文聚焦于制药行业的药丸外观缺陷检测这一具体应用,深入探讨了如何利用海康威视VisionMaster视觉平台,结合**Blob分析**与**

weixin_32903229的博客 311

【深度学习新浪潮】OpenClaw跟机器人行业有哪些很好的研究结合点?

OpenClaw正通过"AI大脑+机器人肢体"的深度融合,重新定义机器人与人类的交互方式和自主操作能力。近期ROSClaw框架发布、人形机器人集成和空间计算试验等进展,标志着OpenClaw已从概念验证阶段进入实际应用落地期,为机器人行业带来了自然语言控制普及化具身智能平民化和跨平台开发标准化三大变革机遇。

专注:太空算力、AI infra、异构调度、大模型成本工程 228

retrofit遇到的一些坑

一、 @GET("user/token/") Observable<String> gToken(@Url String url, @Query("usertype") int userType); Process: com.gouhuoapp.say, PID: 12519 rx.exceptions.OnErrorNotImplementedException: @Url...

ation_work的专栏 1187

【异常】OpenAI提示内容有误 Invalid prompt: your prompt was flagged as potentially violating our usage policy.

用户需优先调整提示内容,确保符合OpenAI的使用政策。若问题持续,建议结合请求ID和具体代码示例联系官方支持。同时,可参考腾讯云、Microsoft Q&A等平台提供的错误处理实践(如重试机制、日志记录)优化代码健壮性。

奶爸的编程之路,也就一周冷个三天 2061

Retrofit2.0源码完全解析

1 Retrofit 和 Okhttp 的关系 现在android端主流的网络框架就是 retrofit + okhttp,那么,它们之间的关系到底是什么呢,其实,真正做网络请求的是okhttp,retrofit只是对它的进一步封装。既然okhttp已经能够实现网络相关操作了,为什么还需要retrofit呢? 很简单,用一个词就能够解释,adapter,adapter的意思是适配器,可以实现各...

SenchunHuang的博客 454

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Retrofit2.0 源码解析笔记

有关 Retrofit2.0 源码解析的梳理笔记

一个有思想的搬运工 575

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Retrofit2.9.0源码解析

前言 之前讲过了okhttp的超级概括的原理解析,okhttp以它优秀的线程池设计,任务队列的分配和转化以及基于策略模式设计的5大拦截器的使用被广大开发者间接引入。等等,为啥是间接?你点进来的时候相信已经有了答案,当然是因为Retrofit的横空出世。当我们使用okhttp的时候肯定得去封装一层,封装的时候得考虑到主、子线程的切换,api返回值的转化处理等等。当你哼哧哼哧或者嘻嘻哈哈封装完毕后,某个小伙伴说他用不习惯,他更愿意去做成XXXX+YYYY+okhttp的模式。这个时候你是选择把他k.o.还是自

wan_dou_的专栏 491

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

源码解析-retrofit2.0

Retrofit的本质是RESTful的HTTP网络请求框架的封装,网络请求的工作本质是OkHttp完成,而Retrofit只是负责网络请求接口的封装。但是现在这么多人用,也看得出这个框架封装的十分受程序员喜爱。 现在先看目录: 一、Retrofit的使用 二、源码解析   一、Retrofit的使用 我们先来看步骤: 1)创建描述网络请求的接口 2)创建Retrofit实例 3)...

qq_16639803的博客 270

Retrofit 源码解析(2.9.0 版本)

文章目录1、简介2、Retrofit 配置与基本用法2.1 依赖引入与配置2.2 基本用法3、Retrofit 的注解3.1 请求方法注解3.2 请求头注解3.3 请求参数注解3.4 请求和响应格式(标记)注解4、Retrofit 注解的配合使用4.1 @GET 使用4.2 @GET、@Query 使用4.3 @GET、@QueryMap 使用4.4 @POST 使用4.5 @POST、@FormUrlEncoded、@File 使用4.6 @POST、@FormUrlEncoded、@FieldMap 使

u011035026的博客 2290

Retrofit2.0源码解析(简版)

出处:http://www.jianshu.com/p/69a3aff6bfac Retrofit 是square公司开发的一款对OKHttp进行了进一步封装的网络框架,现在也是android网络请求中非常火的一个网络请求框架,最近在准备面试的时候也刚好复习到了这一块,然后花了几天时间简单地看了下Retrofit2.0源码,分享一下。若有不对的地方,欢迎指正。 Retrofit2.

harrain的博客 816
上一篇: Java异常和finlly返回值
下一篇: 关于equals,==,hashCode
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值