Retrofit详解(下)

Android Retrofit详解(retrofit:2.3.0) 目录 1.Retrofit是什么? 2.Retrofit如何使用? 2.1创建HTTP请求的API接口 2.2请求执行 3.注解详情 3.1请求方法注解 3.2标记请求数据类型 3.3注解参数 4.GSON和Converter 5.RxJava和CallAdapter 6.自定义Converter 7.自定义CallAdapter 8.其他说明 8.1Retrofit.... 阅读详情

Retrofit详解(下)

上一篇文件介绍了Retrofit的基本使用,接下来我们通过从源码的角度分析一下Retrofit的实现。

首先看一下它的基本使用方法:

// 1
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
// 2
GitHubService gitHubService = retrofit.create(GitHubService.class);

// 3
Call<List<Repo>> call = gitHubService.listRepos("CharonChui");

// 4
call.enqueue(new Callback<List<Repo>>() {
    @Override
    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
        List<Repo> data = response.body();
        Log.i("@@@", "data size : " + (data == null ? "null" : data.size() + ""));
    }

    @Override
    public void onFailure(Call<List<Repo>> call, Throwable t) {

    }
});

我把上面主要分为4个部分,接下来逐一分析:

1. 创建Retrofit并进行配置。

Retrofit retrofit = new Retrofit.Builder()
  .baseUrl("https://api.github.com/")
  .addConverterFactory(GsonConverterFactory.create())
  .build();

简单的一句话,却埋藏了很多。

这是典型的建造者模式、外观模式

就想平时我们写的下载模块,作为一个公共的模块,我们可以对外提供一个DownloadManager供外界使用,而对于里面的实现我们完全可以闭门造车。

具体baseUrl()、addConverterFactory()方法里面的具体实现就不去看了,比较简单。当然这里也用到了工厂设计模式。

2. 创建对应的服务类

GitHubService gitHubService = retrofit.create(GitHubService.class);

这一部分是如何实现的呢?我们看一下retrofit.create()方法的实现:

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() {
          // 这里的Platform主要是为了检测当前的运行平台,是java还是android,会根据当前的平台来返回默认的CallAdapter
          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);
            }
            // 1,根据动态代理的方法去生成ServiceMethod这里动态代理的方法就是listRepos方法
            ServiceMethod serviceMethod = loadServiceMethod(method);
            // 2,根绝ServiceMethod和参数去生成OkHttpCall,这里args是CharonChui
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            // 3, serviceMethod去进行处理并返回Call对象,拿到这个Call对象才能去执行网络请求。
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

看到Proxy.newProxyInstance()就明白了,这里使用了动态代理。简单的说动态代理是在你要调用某个Class的方法前或后,插入你想要执行的代码。那这里要代理的是什么方法? Call<List<Repo>> call = gitHubService.listRepos("CharonChui");,这里就是listRepos()方法。 就是说在调用listRepos()方法时会被动态代理所拦截,然后执行Proxy.newProxyInstance()里面的InvocationHandler.invoke()中的部分。 而invoke()方法的三个参数分别是啥? 分别是Object proxy: 代理对象,Method method:调用的方法,就是listRepos()方法,Object... args:方法的参数,这里是CharonChui。

有关动态代理介绍可以看张孝祥老师的java1.5高新技术系列中的动态代理

这里就不仔细介绍动态代理了,上面的代码中又分为三部分:

  • loadServiceMethod()
  • new OkHttpCall()
  • serviceMethod.callAdapter.adapt()

我们这里分别来进行分析。

  • loadServiceMethod()
    实现如下:

    ServiceMethod loadServiceMethod(Method method) {
        ServiceMethod result;
        synchronized (serviceMethodCache) {
          // ServiceMethod包含了请求的所有相关数据,以及获取请求的request和把请求结果转换成java对象,所以相比较而言较重,用缓存来提高效率。
          result = serviceMethodCache.get(method);
          if (result == null) {
            // build
            result = new ServiceMethod.Builder(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }

    会通过缓存的方式来获取一个ServiceMethod类。通过缓存来保证同一个API的同一个方法只会创建一次。
    有关ServiceMethod类的文档介绍是:

    Adapts an invocation of an interface method into an HTTP call.

    大体翻译一下就是将一个请求接口的方法转换到Http Call中调用。

    而上面第一次使用的时候会通过new ServiceMethod.Builder(this, method).build()创建,那我们看一下它的实现:

    public ServiceMethod build() {
           // 创建CallAdapter用来代理Call
          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用来解析结果将json等返回结果解析成java对象
          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);
            }
            //  解析对应method的注解,这里是listRepos方法的注解。
            Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
            if (parameterAnnotations == null) {
              throw parameterError(p, "No Retrofit annotation found.");
            }
            // 通过注解和参数类型,解析并赋值到parameterHandlers中
            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.");
          }
          // 创建`ServiceMethod()`对象
          return new ServiceMethod<>(this);
        }

    总起来说,就是创建CallAdapter、responseConverter、解析注解、设置参数,然后创建ServiceMethod对象。

    而ServiceMethod的构造函数如下:

    ServiceMethod(Builder<T> builder) {
        this.callFactory = builder.retrofit.callFactory();
        this.callAdapter = builder.callAdapter;
        this.baseUrl = builder.retrofit.baseUrl();
        this.responseConverter = builder.responseConverter;
        this.httpMethod = builder.httpMethod;
        this.relativeUrl = builder.relativeUrl;
        this.headers = builder.headers;
        this.contentType = builder.contentType;
        this.hasBody = builder.hasBody;
        this.isFormEncoded = builder.isFormEncoded;
        this.isMultipart = builder.isMultipart;
        this.parameterHandlers = builder.parameterHandlers;
      }

    看到吗? 这一部分我们应该都稍微有点印象,因为在上一篇文章介绍使用方法的时候,基本会用到这里。

至于这里的CallAdapter、ResponseConverter、Headers、ParamterHandlers等这里就不分析了,最后我们再简单介绍下。

  • 创建OkHttpCall

    接下来会创建OkHttpCall,而OkHttpCall是Call的子类,那Call是什么鬼? 它是具体的网络请求类。

    文档中对Call类的介绍如下:

    /**
     * An invocation of a Retrofit method that sends a request to a webserver and returns a response.
     * Each call yields its own HTTP request and response pair. Use {@link #clone} to make multiple
     * calls with the same parameters to the same webserver; this may be used to implement polling or
     * to retry a failed call.
     *
     * <p>Calls may be executed synchronously with {@link #execute}, or asynchronously with {@link
     * #enqueue}. In either case the call can be canceled at any time with {@link #cancel}. A call that
     * is busy writing its request or reading its response may receive a {@link IOException}; this is
     * working as designed.
     *
     * @param <T> Successful response body type.
     */
    public interface Call<T> extends Cloneable {
        // 这里我特地把这句话放上,Call集成了Cloneable接口。
        // 每一个 call 对象实例只能被用一次,所以说 request 和 response 都是一一对应的。你其实可以通过 Clone 方法来创建一个一模一样的实例,这个开销是很小的。比如说:你可以在每次决定发请求前 clone 一个之前的实例。
        ....
    }

    Retrofit底层默认使用OkHttp,所以当然要创建OkHttpCall了。

    • serviceMethod.callAdapter.adapt(okHttpCall)

    这个CallApdater是什么鬼?

    /**
     * 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.
     */

    可以很简单的看出来这是一个结果类型转换的类。就是Call的适配器,作用就是创建/转换Call对象,把Call转换成预期的格式。CallAdatper创建是通过CallAdapter.factory工厂类进行的。DefaultCallAdapter为Retrofit2自带默认Call转换器,用来生成OKHTTP的call请求调用。

    而它里面的adapt()方法的作用呢?

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

    所以分析到这里我们基本明白了retrofit.create()方法的作用,就是将请求接口的服务类转换成Call,然后将Call的结果转换成实体类。

3. 调用方法,得到Call对象

Call<List<Repo>> call = gitHubService.listRepos("CharonChui");

这个就不分析了,就是在ServiceMethod中返回的Call。

4. 调用Call.enqueue()

在上面分析了,这个Call其实是OkHttpCall,那我们来看一下OkHttpCall.enqueue()方法的实现:

@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 {
          // 调用createRawCall()方法创建Call
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }

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

    if (canceled) {
      call.cancel();
    }
    // 把请求任务加入到okhttp的请求队列中,执行网络请求,注意这里的Call是okhttp3.Call
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          // 解析结果,该方法内部会将OkHttp中Request的执行结果转换成对应的Java对象。
          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();
        }
      }
    });
  }

上面的部分也主要分为三部分:

  • 创建Call
  • 执行网络请求
  • 解析结果
第一部分:创建Call

我们分别进行分析,首先是createRawCall()方法的实现:

private okhttp3.Call createRawCall() throws IOException {
  // ServiceMethod.toRequest()方法的作用是将ServiceMethod中的网络请求相关的数据转换成一个OkHttp的网络请求所需要的Request对象。因为之前分析过所有Retrofit解析的网络请求相关的数据都是在ServiceMethod中
  Request request = serviceMethod.toRequest(args);
  // 调用Factory.newCall方法
  okhttp3.Call call = serviceMethod.callFactory.newCall(request);
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

然后看一下Factory.newCall()方法:

interface Factory {
    Call newCall(Request request);
  }

它的实现类是OkHttpClient类中的newCall()方法,并且创建RealCall对象:

@Override public Call newCall(Request request) {
    return new RealCall(this, request);
  }
第二部分:执行网络请求

这一部分是在call.enqueue()方法中执行的,上面我们分析了创建的Call最终是RealCall类,所以这里直接到看RealCall.enqueue()方法:

@Override public void enqueue(Callback responseCallback) {
    enqueue(responseCallback, false);
  }

  void enqueue(Callback responseCallback, boolean forWebSocket) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }

    // 调用OkHttpClient中的Dispatcher中的enqueue方法
    client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
  }

我们接着看client.dispatcher().enqueue()方法:

synchronized void enqueue(AsyncCall call) {
    // maxRequests的个数是64;
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      // 线程池执行
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

而这个参数AsyncCall是什么鬼? 它是RealCall的内部类,它里面的execute()方法是如何实现的? 只要找到该方法的实现就算是完成了。

首先看一下AsyncCall的声明和构造:

final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;
    private final boolean forWebSocket;

    private AsyncCall(Callback responseCallback, boolean forWebSocket) {
      super("OkHttp %s", redactedUrl().toString());
      this.responseCallback = responseCallback;
      this.forWebSocket = forWebSocket;
    }
    ...
  }

NamedRunnable是Runnable的实现类。我们看一下它的execute()方法:

@Override protected void execute() {
      boolean signalledCallback = false;
      try {
        // 获取请求结果
        Response response = getResponseWithInterceptorChain(forWebSocket);
        if (canceled) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          // 将响应结果设置给之前构造函数传递回来的回调
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }

接着看一下RealCall.getResponseWithInterceptorChain():

private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    return chain.proceed(originalRequest);
  }

  class ApplicationInterceptorChain implements Interceptor.Chain {
    private final int index;
    private final Request request;
    private final boolean forWebSocket;

    ApplicationInterceptorChain(int index, Request request, boolean forWebSocket) {
      this.index = index;
      this.request = request;
      this.forWebSocket = forWebSocket;
    }

    @Override public Connection connection() {
      return null;
    }

    @Override public Request request() {
      return request;
    }

    @Override public Response proceed(Request request) throws IOException {
      // If there's another interceptor in the chain, call that.
      if (index < client.interceptors().size()) {
        Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
        Interceptor interceptor = client.interceptors().get(index);
        Response interceptedResponse = interceptor.intercept(chain);

        if (interceptedResponse == null) {
          throw new NullPointerException("application interceptor " + interceptor
              + " returned null");
        }

        return interceptedResponse;
      }

      // No more interceptors. Do HTTP.
      return getResponse(request, forWebSocket);
    }
  }

又会调用getResponse()方法:

/**
   * Performs the request and returns the response. May return null if this call was canceled.
   */
  Response getResponse(Request request, boolean forWebSocket) throws IOException {
    // Copy body metadata to the appropriate request headers.
    RequestBody body = request.body();
    if (body != null) {
      Request.Builder requestBuilder = request.newBuilder();

      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }

      request = requestBuilder.build();
    }

    // Create the initial HTTP engine. Retries and redirects need new engine for each attempt.
    engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);

    int followUpCount = 0;
    while (true) {
      if (canceled) {
        engine.releaseStreamAllocation();
        throw new IOException("Canceled");
      }

      boolean releaseConnection = true;
      try {
        engine.sendRequest();
        engine.readResponse();
        releaseConnection = false;
      } catch (RequestException e) {
        // The attempt to interpret the request failed. Give up.
        throw e.getCause();
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        HttpEngine retryEngine = engine.recover(e.getLastConnectException(), true, null);
        if (retryEngine != null) {
          releaseConnection = false;
          engine = retryEngine;
          continue;
        }
        // Give up; recovery is not possible.
        throw e.getLastConnectException();
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        HttpEngine retryEngine = engine.recover(e, false, null);
        if (retryEngine != null) {
          releaseConnection = false;
          engine = retryEngine;
          continue;
        }

        // Give up; recovery is not possible.
        throw e;
      } finally {
        // We're throwing an unchecked exception. Release any resources.
        if (releaseConnection) {
          StreamAllocation streamAllocation = engine.close();
          streamAllocation.release();
        }
      }

      Response response = engine.getResponse();
      Request followUp = engine.followUpRequest();

      if (followUp == null) {
        if (!forWebSocket) {
          engine.releaseStreamAllocation();
        }
        return response;
      }

      StreamAllocation streamAllocation = engine.close();

      if (++followUpCount > MAX_FOLLOW_UPS) {
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }

      if (!engine.sameConnection(followUp.url())) {
        streamAllocation.release();
        streamAllocation = null;
      } else if (streamAllocation.stream() != null) {
        throw new IllegalStateException("Closing the body of " + response
            + " didn't close its backing stream. Bad interceptor?");
      }

      request = followUp;
      engine = new HttpEngine(client, request, false, false, forWebSocket, streamAllocation, null,
          response);
    }
  }

完了没有? 完了….

上面只是简单的分析了下大体的调用流程和主要的类,但是好像并没有什么乱用,因为没有具体的去分析里面各部分的实现,如果都分析下来内容太多了。这里就不仔细看了,大体总结一下。

通过上面的分析,最终的网络请求是在OkHttp的Call中去执行,也就是说Retrofit其实是将一个Java接口通过注解等方式来解析参数等然后转换成一个请求交给OkHttp去执行,然后将执行结果进行解析转换暴露给上层调用者。
而这一切是如何实现的呢?
Retrofit非常巧妙的用注解来描述一个HTTP请求,将一个HTTP请求抽象成一个Java接口,然后用了动态代理的方式,动态的将这个接口的注解转换成一个HTTP请求,然后再将这个Http请求交给OkHttp执行。

动态代理用的太妙,而它的过程中也使用了大量的工厂模式,这里就不分析了。

参考:
- simple-http-retrofit-2
- Retrofit API


更多文章请查看AndroidNote

你的star是我的动力!!!

Retrofit 注解参数详解 文章目录GET@Path@Query@QueryMapPOST@Bodyform表单1:@FormUrlEncodedform表单2:FormBody@Multipart上传文件 对Retrofit已经使用了一点时间了,是时候归纳一下各种网络请求的service了。 下面分为GET、POST、DELETE还有PUT的请求,说明@Path、@Query、@QueryMap、@Body、@Field的用法。 添加依赖 implementation 'com.squareup.retrofit2:retrofit 阅读详情

相关推荐

手把手教你用CEFSharp打造防关联指纹浏览器(附完整代码)

本文详细介绍了如何基于CEFSharp框架,从零开始构建一个企业级的防关联指纹浏览器。通过剖析核心架构、多进程隔离实现、动态指纹混淆(如Canvas、WebGL)的实战代码,以及代理集成与性能优化,为跨境电商、广告投放等场景提供了一套可控、安全的开源解决方案。

fern8的博客 961

GitHub之Retrofit使用

Retrofit是Square公司开发的一款针对Android网络请求的框架,本文简要介绍如何使用Retrofit 1.在app\build.gradle中添加依赖 dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compi

时光的博客 2515

2025最新正版Autodesk 3ds Max 2022安装教程:从下载到中文环境配置全流程解析

Autodesk 3ds Max 2022是一款专业的三维建模、动画和渲染软件,广泛应用于影视制作、游戏开发、建筑可视化等领域。

waicsdn_haha的博客 1万+

高级工程师的不二之选,Github常年霸榜的超强框架

每个Android开发者在产品开发的过程中,都需要用到网络和服务器进行交互。而对于网络框架的使用和理解,往往可以看出一个开发者到底处于什么段位: 初级工程师:虽然也会使用OkHttp、Retrofit等框架,但基本都是机械的套用,对其源码、核心原理所知甚少,需要付出大量的时间研究源码。 中级工程师:对于常见网络框架的内部原理有些了解,在项目开发过程中往往都能根据业务需求选用合适的框架。但遇到问题的时候还是经常需要寻求开源方案支持,通常这个时候他们会自行设计一个尽可能小的封装。 高级工程师:一般会

大模型训练 4167

VS2015+C++实战:手把手教你用海康MVS里的Demo搞定多相机同步采图与保存

本文详细解析了在VS2015+C++环境下,利用海康威视MVS工业相机SDK实现多相机同步采图与保存的全流程。从环境准备、SDK选择到多相机初始化、同步采图方案,再到异常处理与性能优化,提供了实战技巧和代码示例,帮助开发者快速掌握工业相机二次开发的核心技术。

weixin_29170327的博客 281

飞控芯片的隐形战场:传感器冗余与实时OS的可靠性革命

本文深入探讨飞控芯片在工业级无人机中的可靠性设计,聚焦传感器冗余架构与实时操作系统(RTOS)的容错机制。通过多IMU备份、自适应加权融合算法及NuttX、ChibiOS等RTOS的故障隔离技术,确保系统在极端环境下毫秒级自愈。文章还涵盖开源生态如PX4的跨平台移植及RISC-V架构的应用,为高可靠性飞控系统提供关键技术参考。

z5a6b的博客 877

Retrofit 使用

Retrofit的使用

qq1302526289的博客 498

S32K144(14)ADC

1、简介 开发板S32K144+S32DS+JLINK,裸机版的程序编写 S32K14x包含两个12位ADC模块,ADC0和ADC1 应用程序可能需要ADC的连续采样(4K采样/秒),这可能对CPU有相当大的负载。虽然使用可编程延迟块(PDB)来触发ADC可能会减少一些CPU负载,但当ADC以非常高的速率采样或PDB被绕过时,ADC支持DMA请求功能以获得更高的性能。ADC可以在转换完成时触发DMA(通过DMA请求)。TRGMUX会根据不同的应用需求,使用软件为用户提供更灵活的DMA触发方案,例如,可

朗朗上口就行啦的博客 1万+

android开源库—retrofit(附实战源码)

概述 使用说明 应用 总结1.概述Retrofit是Square公司开发的一个类型安全的Android和Java的REST客户端库。 GitHub地址:https://github.com/square/retrofit 官方使用说明:http://square.github.io/retrofit/ 在介绍retrofit之前,先了解下RESTFUL风格:RESTFUL:一种软件架构风格,设计风格

跨语言,跨平台,跨应用 1126

TC3XX - MCAL知识点(三十七):AURIX™ TC3xx 的BootLoader烧录APP完成之后跳转使多个核均正常运行

摘要:针对AURIX TC3xx多核芯片在软件复位后仅Core0能启动的问题,分析发现该芯片在Cold Power-on Reset(断电复位)时会完整执行多核启动流程,而Application Reset(软件复位)会跳过从核初始化。解决方案包括:1)在BootLoader中显式调用IfxCpu_startCore()函数启动其他核;2)通过跳转函数强制各核从指定地址启动;3)双Boot场景下让每个核独立响应复位命令。实测表明,软件复位后需手动触发从核启动,或采用断电复位方式确保所有核正常初始化。

梦想技术家 408

可疑物品遗留检测系统:基于YOLOv8的智能安防解决方案

数据采集与标注模块:负责收集和标注可疑物品图像数据模型训练模块:基于YOLOv8算法训练检测模型推理检测模块:加载训练好的模型进行实时检测用户界面模块:提供友好的操作界面和可视化结果展示报警模块:当检测到可疑物品时触发报警机制:包含多种暴力场景和可疑物品SUAVe:监控场景下的异常行为与物品数据集:包含多种可疑物品自建数据集:针对特定场景收集的数据背包(backpack)手提箱(suitcase)无人看管的包裹(package)可疑箱子(box)

YOLO 435

Github上 简单易用的 Android ViewModel Retrofit框架

长期更新 支持网络请求的ViewMode框架 RequestViewModel 【ViewModel+LiveData+Retrofit】

wojiaomtaa的博客 1515

6、 实时家禽健康识别与疾病检测系统的深入解析

本文深入解析了一种基于物联网的实时家禽健康识别与疾病检测系统,结合图像分析和音频分析技术,能够有效识别病鸡并防止疾病传播。文章详细介绍了系统的测试环境、数据采集与预处理方法、图像与音频分析流程,并对系统性能进行了全面评估。最后提出了未来改进方向,包括多模态融合、深度学习应用及实时性优化等。

weixin_28840811的博客 186

Retrofit详解

一:Retrofit是什么? 准确来说,Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。 原因:网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装 我们先来看看下面这个图: 上图说明了如下几点: 1. App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之 后由 OkHttp 完成后续的请求操作。 2. 在服务端返回数据之后,OkHttp 将原始的结果交给

qq_30621333的博客 3万+

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Devexpress16.2.6破解工具

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

Android Retrofit详解

前言 Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装,网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装 使用步骤 1.添加Retrofit库的依赖: implementation 'com.squareup.retrofit2:retrofit:2.0.2' implementation 'com.squareup.retrofit2:converter-gson:2.0.2' implementation 'com.google.

m0_46527751的博客 7085

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

【Retrofit】Retrofit原理解析之注解详解篇

学而不思则罔,思而不学则殆 【Retrofit】Retrofit原理解析之注解详解篇

珍心 1252

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Retrofit用法详解

一、 简介Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,大量的app都采用OkHttp做网络请求,其源码详见OkHttp Github。 本文全部是在Retrofit2.0+版本基础上论述,所用例子全部来自豆瓣Api 首先先来看一个完整Get请求是如何实现: 创建业务请求接

Dylan Dev Blog 7万+

Kotlin中使用Retrofit

Retrofit A type-safe HTTP client for Android and Java Rerofit是Andorid最流行的HTTP框架,可以帮助开发者用最简单的代码实现API的调用。 本文主要介绍Kotlin中Retrofit的基本使用方法, 以帮助初学者快速入门 retrofit完整的使用涉及下面几个步骤: gradle配置 实现interfact 定义...

移动端开发干货分享 1万+

Retrofit

根据这张思维导图,我们开始这篇文章的学习 Retrofit到底是什么 Retrofit主要是对Android网络请求的框架的封装,它遵循Restful设计风格,底层基于OkHttp。 换句说,网络请求的工作本质上是OkHttp完成,而Retrofit仅负责网络请求接口的封装。 主要是使用Retrofit接口封装请求参数、header头部、Url信息等,然后交给OkHttp完成后续的网络请求,当服...

lady_zhou的博客 1939

【Android】Retrofit入门详解

简介:大三学生党一枚!主攻Android开发,对于Web和后端均有了解。 个人语录:取乎其上,得乎其中,取乎其中,得乎其下,以顶级态度写好一篇的博客。 Retrofit入门一.Retrofit介绍二.Retrofit注解2.1 请求方法注解2.1.1 GET请求2.1.2 POST请求2.2 标记类注解2.2.1 FormUrlEncoded2.2.2 Multipart2.2.3 Streaming2.3 参数类注解2.3.1 Header和Headers2.3.2 Body2.3.3 Path2.3.4

weixin_43927892的博客 2131

Retrofit的使用及原理详解

retrofit—>建造者—>create(动态代理)—>getPersonInfo接口(注解解析+URL拼接)到invoke方法中—>call.enqueue(丢给okHttp,realCall—>AsyncCall内部类,切到子线程)—> ExecutorCallAdapterFactory中返回数据的enqueue()方法(切回主线程callbackExecutor.execute())...

java521666的博客 1381

Retrofit 基础+详解

1、什么是retrofit retrofit是网络请求框架,可以理解为okHttp的加强版,底层邓庄了OKH

u014231961的专栏 1783

retrofit用法详解

综述   retrofit是由square公司开发的。square在github上发布了很多优秀的Android开源项目。例如:otto(事件总线),leakcanary(排查内存泄露),android-times-square(日历控件),dagger(依赖注入),picasso(异步加载图片),okhttp(网络请求),retrofit(网络请求)等等。更多square上的开源项目我们可以去...

jim1451的博客 718

Retrofit执行原理详解

Retrofit执行原理就是,通过执行内部方法create作为接口请求的起始。进入通过执行动态代理生成接口对象,调用接口对象方法并回调动态代理的invoke方法。在回调invoke方法过程中,会解析接口对象方法的注解、方法参数注解、方法返回值类型并将解析内容封装成对象。待执行到ServiceMethod.invoke()时,Call对象执行同步/异步请求,使得OkHttp的拦截器通过chain.proceed()传入request对象(通过已解析的注解内容所生成),然后执行最终的接口数据请求,并返回响应报文

文化园 1909

【Retrofit】Retrofit原理解析之原理篇

学而不思则罔,思而不学则殆 【Retrofit】Retrofit原理解析之原理篇引言整体流程 系列文章 【Retrofit】Retrofit原理解析之使用篇 【Retrofit】Retrofit原理解析之原理篇 引言 在上一篇文章中,分享讲了Retrofit框架的常见使用范例,本篇分享来说一下Retrofit的的原理 整体流程 整体流程 新建Retrofit实例,通过构建者模式设置一些参数工厂(用来数据封装+数据解析) 调用Retrofit.create(),方法拿到自定义服务的实例 调用服务的具体

珍心 729

Retrofit源码学习四:Retrofit源码详解二

目录 系列文章: RxjavaCallAdapterFactory内部构造与工作原理解析: Retrofit中网络请求接口实例解析: Retrofit中serviceMethod对象解析 Retrofit中okHttpCall对象和adapt返回对象解析 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args...

songzi1228的博客 342
上一篇: Retrofit详解(上)
下一篇: DLNA
CharonChui
博客等级 码龄12年 66粉丝 134原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值