okhttp源码分析

okhttp3源码分析之AsyncTimeout 继承自Timeout, 使后台线程在发生超时时准确执行操作。用来实现本机不支持的超时。 公开方法: final void enter() 调用了private static synchronized void scheduleTimeout,确定链表关系(当前node上个的next和this的header前后关系)。 private static synchronized void s... 阅读详情

okhttp是一款强大的网络访问框架,使用很久了,通过源码分析,将理解到okhttp的加载流程和设计理念,以及一些核心OkHttpClient、Request、RealCall、Dispatcher、Interceptor等核心类的作用。按照他的加载流程进行分析,先来看看最简单的get请求:

    OkHttpClient okHttpClient = new OkHttpClient();
    Request request = new Request.Builder()
            .url("https://www.baidu.com/")
            .build();
    Call call = okHttpClient.newCall(request);
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {

        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {

        }
    });

从上面的可以看出okhttp的get请求过程主要进行了三大步。分别是创建客户端、创建请求信息、包装请求信息、发起请求。因此我们按照这三大步骤进行逐个分析,在分析过程中尽量使用通俗易懂的话语对程进行一个总结。

一、OkHttpClient初始化流程

OkHttpClient被称为okhttp的客户端,在创建对象时候,OkHttpClient调用自己的另一个携带参数Bulider的构造方法B。传递过去得参数为new Bulider,这里的Bulider是它的内部类,创建Builder的时候,Builder的构造方法初始化了一些参数给自己的成员变量赋值这时候。这时候在B构造方法中获得传递过来的Builder,调用Builder的成员变量给OkHttpClient成员变量赋值,OkHttpClient的成员变量的大部分值都可以通过builder.变量名称获得,获取不到的,在本类中获取,这时候OkHttpClient初始化数据结束。简化伪代码如下:

    public class OkHttpClient {
        final int readTime;
        public OkHttpClient(){
            this(new Builder());
        }

        public OkHttpClient(Builder builder) {
            this.readTime  = builder.readTime;
        }

        public static final class Builder {
            private int readTime;
            public Builder(){
                readTime = 20;
            }
        }

        public int defaultReadTime(){
            return readTime;
        }
    }

很明显OkHttpClient的创建时使用了建造者设计模式,这种设计模式又称为生成器设计模式,其实在后面的Request、Response等对象的创建中也采用了这种设计模式,后面就不再介绍其创建过程了。因此在平时的开发中如果配置的参数信息量非常多也应该采用这种模式。

二、Request的创建过程

Request的主要功能是创建请求数据,在Request的类中有一个Builder内部类,参数的配置是通过他进行,包括url,请求方法、请求体、请求tag等等,配置好之后通过build进行创建返回Request对象。这里也是采用建造者模式,如上,不在贴上源码了。

三、请求数据的生成过程

Request对象虽然配置好了请求信息,但是他不直接参与请求的业务过程,仅仅是包含请求的信息,体现了他的单一职责。真正的请求数据的生成是在RealCall中。将Request请求信息传进OkHttpClient客户端的newCall方法中,返回RealCall实例对象,RealCall包装了请求信息和一些回调信息。如下可以看出来,他间接调用RealCall的newRealCall方法。

  @Override
  public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

RealCall实现了Call接口,在这个方法里面传递进去上面创建的Request和OkHttpClient。然后通过new RealCall自己创建自己的实例对象call,在RealCall的构造方法中初始化RealCall的一些数据,这样call就生成了。在这个过程中还进行了一个操作是通过OkHttpClient的获取到监听请求过程的生命周期的接口。最后返回这个call。

  static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    //注意这里对RetryAndFollowUpInterceptor拦截器进行了一个初始化,后面会介绍
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
  }

四、请求的发起过程

请求的发起是通过Call的enqueue方法进行请求。这个Call来自于上一步的RealCall的实例,找到对应的enqueue方法,首先会检查这个请求是否被执行过,请求过的话会被标记,然后调用上一步初始化的生命周期方法的start方法,表明请求开始了;然后把这个Call进行包装为一个AsyncCall类里面,进行请求。

	  @Override
	  public void enqueue(Callback responseCallback) {
	  //判断是否已经执行过了本次请求,执行过的话标记为true
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        //记录请求的信息
        captureCallStackTrace();
        //设置开始请求回调
        eventListener.callStart(this);
        //执行请求
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
      }

从上面可以看出dispatcher方法来自于OkHttpClient对象,通过这个enqueue方法进行请求。

五、Dispatcher的请求过程

Dispatcher是一个调度器,用于对任务的调度分发过程,为了管理所有的请求,Dispatcher采用了队列+生产+消费的模式。里面包含了三个ArrayDeque双端队列,这种双端能够解决在频繁出队的情况下产生的假溢出现象,非常适合这种环境。同时规定了最大的请求数量为64个,最大的请求host个数为5个。如下:

  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;

  /** 当资源不足时候进行缓存 */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** 管理所有的异步请求 */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** 管理所有的同步请求 */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

初步了解了Dispatcher之后来看看enqueue方法,首先判断如果正在运行的队列里面的call小于最大数量,并且请求的host的数量小于最大数量则将当前的call加入到正在运行的队列里面,进行请求。否则添加到缓存队列里面。

  synchronized void enqueue(AsyncCall call) {

    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      //将call加入到正在运行的队列里面
      runningAsyncCalls.add(call);
      //开始执行请求
      executorService().execute(call);
    } else {
       //添加到缓存队列里面
      readyAsyncCalls.add(call);
    }
  }

六、请求线程的创建

在上一步满足条件开始请求会从executorService获取线程池对象。

  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

可以看出他的核心线程数为0,最大线程数为Integer.MAX_VALUE,空闲线程的存活时间是60秒,任务队列为没有容量的SysnchronousQueue作为线程池的工作队列,线程名称为OkHttp Dispatcher。这个和Executors.newCachedThreadPool()可缓存的线程池非常像。

七、请求任务的封装

    在请求线程创建好之后就需要创建请求任务,在上面的第五步中可以看出请求任务传递的是一个AsyncCall,它来自于第四步的new AsyncCall(responseCallback),,AsyncCall就是RealCall的一个final类型的内部类,他继承自NamedRunnable,NamedRunnable实现了Runnable接口,重写run方法,而AsyncCall的execute就是run方法的具体实现类。直接看execute方法:

    @Override
    protected void execute() {
        boolean signalledCallback = false;
        try {
            //请求各个拦截链获得响应 ——1
            Response response = getResponseWithInterceptorChain();
            if (retryAndFollowUpInterceptor.isCanceled()) {
               //请求被取消,设置失败回调
                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 {
                eventListener.callFailed(RealCall.this, e);
                responseCallback.onFailure(RealCall.this, e);
            }
        } finally {
            //一轮请求完成 ——2
            client.dispatcher().finished(this);
        }
    }

这一部分是Okhttp请求的核心部分,所有的请求过程都封装在这里面,包括三大部分:第一、请求拦截器生成请求数据;第二、请数据回调,第三、请求完成之后的处理,下面对这一、三部分进行详细说明。

八、拦截链的请求过程

Interceptor拦截器,是OkHttp的核心,Call、Callback和Dispatcher虽然很有用,但对于解决复杂的网络请求没有太多作用,使用了分层设计的拦截器Interceptor才是解决复杂网络请求的核心,这也是OkHttp的核心设计。网络编程有七层,每层都有每层的含义,层层依赖,但每层都各司其职,OkHttp也采用了分层设计思想,每层Interceptor的输入都是Request,输出都是Response,所以可以一层层地加工Request,再一层层地加工Response。每一层是通过一个链将其连接起来。所以要了解okhttp的请求内容、重试机制、缓存、回调等核心思想就需要分析这些系统拦截器的源码进行深入了解。

不管是同步请求还是异步请求,最终都会调用拦截器来处理网络请求。上一步中标注的——1中就是拦截器的请求部分,是OkHttp的精髓所在:

  Response response = getResponseWithInterceptorChain();

通过过getResponseWithInterceptorChain这个方法,他会生成Interceptor集合,里面添加各种拦截器,例如重试、缓存、拦截、网络等拦截器,然后根据这一系列的拦截器构建出一个Interceptor.Chain实例对象,之后调用RealInterceptorChain的processed方法。如下:

  Response getResponseWithInterceptorChain() throws IOException {
    //创建拦截器集合
    List<Interceptor> interceptors = new ArrayList<>();
    //自定义应用拦截器
    interceptors.addAll(client.interceptors());
    //重试拦截器
    interceptors.add(retryAndFollowUpInterceptor);
    //桥接拦截器
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //缓存拦截器
    interceptors.add(new CacheInterceptor(client.internalCache()));
    //连接拦截器
    interceptors.add(new ConnectInterceptor(client));
    //自定义网络拦截器
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    //在线网络请求拦截器
    interceptors.add(new CallServerInterceptor(forWebSocket));
    //生成拦截链
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
    //请求
    return chain.proceed(originalRequest);
  }

每个拦截器的具体内容这里不作介绍,后期会加上,这里主要介绍整个请求的流程,详情看上面的备注。找到对应的proceed方法,proceed方法省略了部分代码,便于理解,如下:

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {

      }
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
     //从拦截器例表中获取一个拦截器
    Interceptor interceptor = interceptors.get(index);
    //根据获取到的拦截器和拦截器链获得Response
    Response response = interceptor.intercept(next);

    return response;
  }

上面的interceptor.intercept(next);对应的是每个具体的拦截器的intercept,以重试拦截器为例,为了便于理解删除了部分代码:

     @Override
     public Response intercept(Chain chain) throws IOException {
        //根据拦截器链获取Request、call
        Request request = chain.request();
        RealInterceptorChain realChain = (RealInterceptorChain) chain;
        Call call = realChain.call();
        EventListener eventListener = realChain.eventListener();
        //生成请求链路信息
        StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
            createAddress(request.url()), call, eventListener, callStackTrace);

        while (true) {
          try {
            //重点:
            response = realChain.proceed(request, streamAllocation, null, null);
            releaseConnection = false;
          } catch (RouteException e) {

          }
      }

上面的重点部分:

    response = realChain.proceed(request, streamAllocation, null, null);

可以看出在重试拦截器的intercept方法里面又调用RealInterceptorChain的proceed,有重复了上面的方法,可以推测出,在RealInterceptorChain的proceed方法里面又是调用下一个拦截器有的proceed,事实上就是这样。一直到调用CallServerInterceptor的proceed结束。这样,就形成一个chain.process(intreceptor)-->interceptor.intercept(chain)-->chainprocess(intreceptor)-->interceptor.intercept(chain)的循环,这个过程中,chain不断消费,直至最后一个拦截器,链式调用结束,获得Response。

九、请求队列数据的读取过程

又回到第七步,获取response数据后接着进行设置请求成功、失败、异常的回调,最后执行finally代码:

    finally {
        client.dispatcher().finished(this);
     }

finally对本轮请求数据完成的后期操作。在第五步中,有三个缓存队列,专门用于对call的缓存,当一次请求执行完毕的时候,就需要从队列读取下一次请求了,finished方法就是处理这方面的内容。这里设计的非常好,因为网络请求失败是很常见的场景,必须能在失败时避免阻塞队列。写着在finally里面,不管是请求异常还是正常都会执行这段代码,保证了队列执行不会被阻塞,不会因为请求异常没有执行到队列里面的其他的无法执行。在Dispatcher类中找到对应的方法:

  private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      //重点promoteCalls
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

可以看到这个方法里面加了同步锁synchronized,加同步锁的目的是为了保证从缓存队列里面读取的call加入到正在执行的队列里面数据的有序性,因为readyAsyncCalls队列移动到runningAsyncCalls队列里面,这在多线程场景下并不安全。看重点:

  private void promoteCalls() {
    //正在运行的队列大小超过最大容量,则不进行转移
    if (runningAsyncCalls.size() >= maxRequests) return;
    //正在运行队列为空则返回
    if (readyAsyncCalls.isEmpty()) return;
    //遍历缓存队列
    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();
      //正在运行的host小于最大的
      if (runningCallsForHost(call) < maxRequestsPerHost) {
        //移除call加入到正在运行的队列
        i.remove();
        runningAsyncCalls.add(call);
        //扔进线程池中,执行任务,重复第六步
        executorService().execute(call);
      }
      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

    总结:

以上就是okhttp的加载流程源码分析,现在总结为一张图如下:

 

 

 


 

简洁易懂的 OkHttp 请求的流程源码分析 本文为 OkHttp 的第一篇文章,主要是对整个请求的流程的梳理,对 OkHttp 整体有一个感性的认识。 本文基于 OkHttp 最新的 4.8.1版本进行源分析的,源码是 Kotlin 写的,做好准备。 依赖 implementation 'com.squareup.okhttp3:okhttp:4.8.1' 整体流程 先写一个 Demo 作为源码分析的入口,首先分析异步请求的整体流程,然后再看同步请求的整体流程,从整体上把握 OkHttp 的请求流程 1.OkHttp 的基本使用 class O 阅读详情

相关推荐

OKHttp3源码分析——学习笔记

文章目录1. HttpClient与HttpUrlConnection的区别2. OKHttp源码分析使用步骤:dispatcher任务调度器,Request请求RealCallAsyncCall3. OKHttp架构分析1. 异步请求线程池, Dispather2. 连接池清理线程池- ConnectionPool3. 缓存整理线程池 DisLruCache4. Http2异步事务线程池, ht...

Sincerity_的博客 1380

OkHttp配置HTTPS访问+服务器部署

1 概述 okhttp配置https访问,需要 2 OkHttp介绍 OkHttp是一款开源的处理网络请求的轻量级框架,有Square公司贡献,用于替代HttpUrlConnection与Apache HttpClient,目前Github上有36.4k的star.优点有 共享socket,HTTP/2支持所有连接到同一个主机的请求共享socket 连接池可以减少请求延迟 缓存响应数据减少重复的...

氷泠 5172

Okhttp源码分析&实践(四)【Okhttp的整体框架和基本源码分析】

前面几章,我们学习了http的基础知识,服务端的基础知识、服务端测试Demo的实践编写,本章开始,我们正式开始Okhttp的框架源码学习和实践,大家要紧跟脚步哦,建议大家,可以跟随小编,一点一点的敲一下文章中的代码,相信通过这个系列学习,您不单单会获得okhttp的源码实践知识,更多的可能,会总结得到一份自我学习、实践的方式方法。 1.从使用入手,初探源码 我们先从okhttp的经典使用入手,试着了解、猜测一下okhttp的整体实现逻辑。 OkHttpClient okHttpClient =

itbird的专栏 1076

Okhttp之Https

引子: okhttp是一款开源的网络访问框架,支持http以及https的访问。 今天,我研究的是如何用 okhttp库 来访问https 的站点。 研究的结论先摆出来: 1)如果这个HTTPS站点,是经过了权威证书颁发机构CA的认证,那么你可以像访问普通HTTP那样来访问https。 2)如果这个HTTS站点,没有经过CA认证,那我们有两种方式来访问它。   其一,让okhttpClient信任所有的https,这是比较简单粗暴的做法。   其二,一个比较文艺的做法,下载该https站点的证

chuyouyinghe的专栏 3399

Okhttp源码分析&实践(七)【 实践环节:Okhttp下载功能的实现】

本章从下载的功能需求,到下载框架的设计、开发、运行调试,花费了不少精力。也许一切看上去那么简单,但是从需求、设计、编码、调试,小编中间犯了很多低级的错误,所以每件事情,我们还是要动手去做,可能一些东西并非看上去那么简单,只有自己遇到了,并且利用所学所思,解决了问题或者需求,也许这些知识才真正属于我们自己。

itbird的专栏 966

okhttp3进行https的post调用

okhttp3进行https的post调用。代码比较详细,也有错误说明。

OKHttp实现Https请求

1.HTTPS定义 HTTPS全称为Hyper Text Transfer Protocol over Secure Socket Layer或是Hypertext Transfer Protocol Secure 中文含义为“超文本传输安全协议” 。是以安全为目标的HTTP通道。简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。...

听海的博客 1万+

手把手教你用DCA1000和mmWave Studio 2.0采集AWR1843雷达数据(附驱动安装与常见报错排查)

本文详细介绍了使用DCA1000和mmWave Studio 2.0采集AWR1843毫米波雷达数据的全流程指南,包括硬件连接、驱动安装、软件配置及常见报错排查。通过实战经验分享,帮助开发者快速掌握数据采集技巧,优化雷达参数配置,提升数据质量与采集效率。

weixin_30070339的博客 332

2.OkHttp的初始化

2.OkHttp的初始化OkHttp的整个的初始化采用了一个Builder的形式来建造,对设计模式不太了解的同学可以去看https://github.com/mirsfang/ExamplesOfDesignPatterns接下来进入正题OkHttpClient的初始化OkHttpClient在代码中是这样的 OkHttpClient okHttpClient=new OkHttpClient.Bu

Mirs的博客 2447

SAP物料主数据表结构全解析:ABAP开发与MM模块必知必会

本文深入解析SAP物料主数据的核心表结构,涵盖MARA、MAKT、MARC、MARD及MVKE等关键表。详细阐述了物料主数据在ABAP开发和MM模块中的存储逻辑与关联关系,帮助开发者和顾问高效处理数据查询、增强功能及业务故障排查,是掌握SAP物料管理基础的必读指南。

weixin_29216957的博客 379

Mathtype公式下标深度调整技巧:解决固定行距下的显示不全问题

本文针对在Word等文档中设置固定行距时,Mathtype公式下标显示不全的问题,提供了专业解决方案。核心在于调整Mathtype软件内部的“下标深度”参数,通过修改单个公式或批量格式化全文,使公式完美适配固定行距,确保下标清晰完整,且不影响文档整体排版。

pepsi的博客 1497

OkHttp源码分析

https://github.com/square/okhttp 一,OKHttp介绍 okhttp是一个第三方类库,用于android中请求网络。 这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso和LeakCanary) 。用于替代HttpUrlConnection和Apache HttpClient(android API23...

旧时光っ 722

从PHY芯片看工业网络精准时钟:IEEE 1588v2(PTP)协议实现与选型指南

本文深入解析了工业网络中IEEE 1588v2(PTP)协议的实现与PHY芯片选型要点。通过对比KG7101、RTL8211F等芯片的关键参数,揭示硬件时间戳对纳秒级时钟同步的决定性作用,并提供PTP网络设计中的拓扑布局与配置优化技巧,助力工业自动化场景实现精准时间同步。

weixin_42628688的博客 500

Okhttp3源码分析之一

一、OKHTTP简介 OKHttp是一个处理网络请求的开源项目OKHttp GitHub地址 OKHttp优点 支持HTTP2/SPDY(SPDY是Google开发的基于TCP的传输层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。) socket自动选择最好路线,并支持自动重连,拥有自动维护的socket连接池,减少握手次数,减少了请求延迟,共享Socket,减少对服务器...

jy专栏 334

Synopsys安装教程Ubuntu22.04版本

在Ubuntu22版本上安装Synopsys等系列工具,安装DC,VCS等等

qq_59529218的博客 5721

RT-Thread Studio使用笔记(四):带片外Flash(W25Q128)的OTA(YModem)

前言 在学习OTA之前,请先参考上两篇博客写的关于SPI设备及W25Q128的使用方法,传送门: https://blog.youkuaiyun.com/tigerots/article/details/107423633 https://blog.youkuaiyun.com/tigerots/article/details/107933991 如何使用OTA 一. 制作BootLoader 打开Bootloader 在线获取地址,注册,并根据RT-thread官方文档生成BootLoader,官方文档已经写的很清楚,再此

tigerots的专栏 4007

okhttp3 底层源码分析

okhttp3源码分析之请求流程:链接地址 okhttp3源码分析之拦截器:链接地址

悟-静的博客 553

四舵轮底盘运动学模型(源码)(四轮四独立转向)二

舵轮4转向活动范围 x 轴正半轴,x轴正方向为0弧度,左正右负, -M_PI/2 < 转向范围 < M_PI/2;移动底盘的正前方为x方向,左侧为y轴方向(遵循右手坐标系,右手大拇指指向天空为z轴方向,食指与中指垂直,食指指向小车正前方为x轴,中指指向为移动底盘y轴方向)转向:逆时针旋转角速度w为正,顺时针旋转角速度w为负。(遵循右手螺旋法则,右手握拳大拇指指向天空为旋转z轴方向,拳垂直于地面,4指方向即底盘转动的正方向)左前轮为1号轮,右前轮为2号轮,左后轮为3号轮,右后轮为4号轮。

苏凯的博客 527

OkHttp简单使用及源码分析

文章目录简单使用源码分析整体架构简介Interface——接口层Protocol——协议层Connection——连接层Cache——缓存层:管理本地缓存I/O——I/O层:实际数据读写实现Inteceptor——拦截器层:拦截网络访问,插入拦截逻辑Interface——接口层OkHttpClientRequestCallcall.execute()call.enqueue(callback)ca...

yjh728的博客 796

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

okhttp依赖_简洁易懂的 OkHttp 请求的流程源码分析

本文为 OkHttp 的第一篇文章,主要是对整个请求的流程的梳理,对 OkHttp 整体有一个感性的认识。 本文基于 OkHttp 最新的 4.8.1版本进行源分析的,源码是 Kotlin 写的,做好准备。依赖implementation 'com.squareup.okhttp3:okhttp:4.8.1'整体流程先写一个 Demo 作为源码分析的入口,首先分析异步请求的整体流程,然后再看同步请...

weixin_39584571的博客 288

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Okhttp同步请求源码分析

进阶android,OKhttp源码分析——同步请求的源码分析 OKhttp是我们经常用到的框架,作为开发者们,我们不单单要学会灵活使用,还要知道他的源码是如何设计的。 今天我们来分析一下OKhttp 同步请求的执行流程和源码分析 so,老样子,我们先来一张图 从上图可以看出,不管是同步请求还是异步请求,我们都需要创建一个OKhttpClient对象,用到的是build构造者模式,创建Reque...

这个时代,作为程序员可能要学习小程序 629

SAP B1中文培訓教材_SDK

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

开源库源码分析:Okhttp源码分析(一)

接下来就要开始分析一些常用开源库的源码了,作为最常用的网络请求库,OkHttp以其强大的功能深受Android开发者的喜爱(比如说我),还有对该库进行二次封装而成的热门库,比如说Retrofit。本文我们将从源码入手看看OkHttp是如何运作的。注意本文解析的是OkHttp3库,该库是用Kotlin写的,需要大家有一些Kotlin基础。

Tai_Monster的博客 4525
上一篇: hash冲突的解方法
下一篇: Recycleview的联动效果
一杯清泉
博客等级 码龄11年 314粉丝 210原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值