首页 > 其他分享 >Android面试:OkHttp 详解

Android面试:OkHttp 详解

时间:2024-09-23 23:49:54浏览次数:10  
标签:拦截器 请求 自定义 OkHttpClient 缓存 详解 OkHttp Android

引言

        在 Android 开发中,网络请求是不可或缺的一部分。OkHttp 作为一款强大的 HTTP 客户端库,以其高效、易用和灵活的特点,成为了 Android 开发者的首选。本文将深入解析 OkHttp 的内部机制,包括其架构、基本使用、核心组件以及如何通过扩展来实现更丰富的功能。

1、OkHttp 的基本架构

        OkHttp 的设计基于几个核心组件,包括 OkHttpClientDispatcherInterceptorCall 和 Response。这些组件共同协作,完成 HTTP 请求的发送和响应的接收。

  • OkHttpClient:作为 OkHttp 的核心类,负责配置和管理 HTTP 请求。通过 OkHttpClient.Builder 可以设置各种请求参数,如超时时间、拦截器、缓存等。
  • Dispatcher:负责异步请求的调度。它内部维护了一个线程池,用于执行网络请求。Dispatcher 还负责请求的排队、执行和取消等操作。
  • Interceptor:拦截器是 OkHttp 的一个强大特性,允许开发者在请求发送前或响应接收后插入自定义逻辑。OkHttp 内置了多个拦截器,如 BridgeInterceptorCacheInterceptorConnectInterceptor 和 CallServerInterceptor 等。
  • Call:代表一个 HTTP 请求。通过 OkHttpClient.newCall() 方法可以创建一个 Call 对象,然后调用其 enqueue() 或 execute() 方法来发送请求。
  • Response:代表 HTTP 响应。包含了响应的状态码、响应头和响应体等信息。
2、OkHttp 的基本使用

        OkHttp 的使用非常简单,以下是一个基本的 GET 请求示例:

OkHttpClient client = new OkHttpClient();  
  
Request request = new Request.Builder()  
        .url("http://www.example.com")  
        .build();  
  
client.newCall(request).enqueue(new Callback() {  
    @Override  
    public void onFailure(Call call, IOException e) {  
        e.printStackTrace();  
    }  
  
    @Override  
    public void onResponse(Call call, Response response) throws IOException {  
        if (response.isSuccessful()) {  
            String responseBody = response.body().string();  
            // 处理响应体  
        }  
    }  
});

        除了直接创建 OkHttpClient 实例外,还可以使用 OkHttpClient.Builder 来配置客户端,如设置超时时间、添加拦截器等:

OkHttpClient.Builder builder = new OkHttpClient.Builder();  
builder.connectTimeout(10, TimeUnit.SECONDS) // 设置连接超时时间  
       .readTimeout(30, TimeUnit.SECONDS)    // 设置读取超时时间  
       .writeTimeout(30, TimeUnit.SECONDS)   // 设置写入超时时间  
       .addInterceptor(new MyInterceptor()); // 添加自定义拦截器  
  
OkHttpClient client = builder.build();
3、核心组件详解
3.1、Dispatcher

        Dispatcher 是 OkHttp 的调度器,负责异步请求的调度和执行。它内部维护了一个线程池(默认为 Dispatcher 类中的静态常量 EXECUTOR_SERVICE),用于执行网络请求。Dispatcher 还负责请求的排队、执行和取消等操作。

当调用 Call.enqueue() 方法时,请求会被封装成一个 AsyncCall 对象,并添加到 Dispatcher 的队列中。Dispatcher 会根据当前线程池的状态和请求的配置(如最大并发数、同一主机的并发数等)来决定是否立即执行该请求。

3.2、Interceptor

        Interceptor 是 OkHttp 的一个强大特性,允许开发者在请求发送前或响应接收后插入自定义逻辑。OkHttp 内置了多个拦截器,这些拦截器按照特定的顺序组成一个拦截器链。当请求发送或响应接收时,会依次调用拦截器链中的每个拦截器的 intercept() 方法。

        以下是一些重要的内置拦截器:

  • BridgeInterceptor:负责设置请求的默认头部信息,如 Content-TypeUser-Agent 等。
  • CacheInterceptor:负责处理请求的缓存逻辑。如果请求可以从缓存中获取到有效的响应,则直接返回缓存中的响应,否则继续执行后续的拦截器。
  • ConnectInterceptor:负责建立与服务器的连接,即 TCP 连接。
  • CallServerInterceptor:负责将请求发送给服务器,并接收服务器的响应。
3.3、Call 和 Response

   Call 代表一个 HTTP 请求,通过 OkHttpClient.newCall() 方法可以创建一个 Call 对象。Call 对象提供了 enqueue() 和 execute() 两个方法来发送请求。enqueue() 方法用于异步请求,而 execute() 方法用于同步请求。

   Response 代表 HTTP 响应,包含了响应的状态码、响应头和响应体等信息。通过调用 response.body() 可以获取到响应体的 ResponseBody 对象,进而读取响应体的内容。

4、OkHttp 的扩展

        OkHttp 的强大之处在于其灵活性和可扩展性。通过自定义拦截器、缓存策略等,可以实现丰富的功能。

4.1、自定义拦截器

        自定义拦截器允许开发者在请求发送前或响应接收后插入自定义逻辑。以下是一个简单的自定义拦截器示例:

public class LoggingInterceptor implements Interceptor {  
    @Override  
    public Response intercept(Chain chain) throws IOException {  
        Request request = chain.request();  
  
        // 在发送请求前打印请求信息  
        long t1 = System.nanoTime();  
        System.out.println(String.format("Sending request %s on %s%n%s",  
                request.url(), chain.connection(), request.headers()));  
  
        Response response = chain.proceed(request);  
  
        // 在接收响应后打印响应信息  
        long t2 = System.nanoTime();  
        System.out.println(String.format("Received response for %s in %.1fms%n%s",  
                response.request().url(), (t2 - t1) / 1e6d, response.headers()));  
  
        return response;  
    }  
}

        将自定义拦截器添加到 OkHttpClient 中:

OkHttpClient.Builder builder = new OkHttpClient.Builder();  
builder.addInterceptor(new LoggingInterceptor());  
OkHttpClient client = builder.build();
4.2、自定义缓存策略

        OkHttp 提供了灵活的缓存策略,允许开发者通过自定义缓存策略来控制缓存的行为。默认情况下,OkHttp 使用 Cache 类来实现缓存功能。但是,开发者也可以通过实现自己的缓存逻辑来替换默认的缓存实现。

        自定义缓存策略通常涉及到以下几个步骤:

  1. 创建自定义缓存类:实现自己的缓存逻辑,如使用 SQLite 数据库、SharedPreferences 或其他存储方式。
  2. 设置自定义缓存:通过 OkHttpClient.Builder 的 cache() 方法设置自定义缓存实例。
4.3、监听网络请求进度

        OkHttp 本身并不直接提供监听网络请求进度的功能。但是,通过自定义拦截器和 ResponseBody,我们可以实现这一功能。

        以下是一个监听网络请求进度的示例:

public class ProgressResponseBody extends ResponseBody {  
    private final ResponseBody responseBody;  
    private final ProgressListener progressListener;  
    private BufferedSource bufferedSource;  
  
    public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {  
        this.responseBody = responseBody;  
        this.progressListener = progressListener;  
    }  
  
    @Override  
    public MediaType contentType() {  
        return responseBody.contentType();  
    }  
  
    @Override  
    public long contentLength() {  
        return responseBody.contentLength();  
    }  
  
    @Override  
    public BufferedSource source() {  
        if (bufferedSource == null) {  
            bufferedSource = Okio.buffer(source(responseBody.source()));  
        }  
        return bufferedSource;  
    }  
  
    private Source source(Source source) {  
        return new ForwardingSource(source) {  
            long totalBytesRead = 0L;  
  
            @Override  
            public long read(Buffer sink, long byteCount) throws IOException {  
                long bytesRead = super.read(sink, byteCount);  
                // 更新已读取的字节数,并通知监听器  
                totalBytesRead += bytesRead != -1 ? bytesRead : 0;  
                progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);  
                return bytesRead;  
            }  
        };  
    }  
  
    public interface ProgressListener {  
        void update(long bytesRead, long contentLength, boolean done);  
    }  
}

   然后,在自定义拦截器中,将原始的 ResponseBody 替换为 ProgressResponseBody

public class ProgressInterceptor implements Interceptor {  
    @Override  
    public Response intercept(Chain chain) throws IOException {  
        Response originalResponse = chain.proceed(chain.request());  
        return originalResponse.newBuilder()  
                .body(new ProgressResponseBody(originalResponse.body(), progressListener))  
                .build();  
    }  
  
    private ProgressResponseBody.ProgressListener progressListener = new ProgressResponseBody.ProgressListener() {  
        @Override  
        public void update(long bytesRead, long contentLength, boolean done) {  
            // 在这里处理进度更新逻辑  
        }  
    };  
}
总结

        OkHttp 作为一款强大的 HTTP 客户端库,在 Android 开发中扮演着重要的角色。

个人网站:www.rebootvip.com
更多SEO优化内容 网站学习 google adsense
资源免费分享下载:电子书,项目源码,项目实战
** ** Python 从入门到精通 ** ** 
** ** Java   从入门到精通 ** ** 
** ** Android从入门到精通 ** ** 

标签:拦截器,请求,自定义,OkHttpClient,缓存,详解,OkHttp,Android
From: https://blog.csdn.net/Ctrl_qun/article/details/142471310

相关文章

  • Python数据库连接池dbutils详解
    简介在python开发中,如果需要连接MySQL数据库并进行数据操作,可以使用dbutils模块,dbutils是python的一个数据库工具库下载对应模块pipinstallpymysqlpipinstalldbutils连接池配置信息说明使用示例importpymysqlfrompymysql.cursorsimportDictCursorfr......
  • Android生产永不重复的数字
    在Android中生成永不重复的数字,通常指的是在一个特定的上下文中(比如在一个应用会话期间或用户登录期间)生成一系列唯一的随机数字。这可以通过多种方式实现,下面给出一个简单的示例,展示如何在一个应用会话中生成一系列不重复的随机数字。方法概述使用集合存储已生成的数字:创建一个集......
  • Java 枚举六种常用的方法详解(超详细讲解)
    目录Java枚举  知识点  概念  枚举的方法  枚举的特性  枚举的应用场景  EnumSet和EnumMapJava枚举知识点概念enum的全称为enumeration,是JDK1.5中引入的新特性。在Java中,被enum关键字修饰的类型就是枚举类型。形式如下:enumColor{RED,......
  • Android Wear 开发 (一),阿里、腾讯、华为、京东等多家大厂最新安卓面试题
    importandroid.support.v4.app.NotificationCompat.WearableExtender;普通通知栏手机:普通的通知栏在手机上的效果应该都不陌生,这里就不展开说明手表:手表端的效果是由2张卡片构成的,第一张是手机通知栏的信息组成,第二张是点击开发手机应用,具体的效果与手机通知栏的点击事......
  • Android与WebView(网页)的使用以及交互,阿里快手拼多多等7家大厂Android面试真题
    <?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android=“http://schemas.android.com/apk/res/android”android:layout_width=“match_parent”android:layout_height=“match_parent”android:orientation=......
  • Android Studio 快捷用法
    AndroidStudio快捷用法路一直都在   原文链接    2017年03月10日发布AndroidStudio已经用了两年左右了,对快捷键的使用一直如同段誉的六脉神剑一般,偶尔会biu不出来,从来没有静下心来耐心的看完Tips,为了避免这种尴尬,决定把Tips完整的练习一遍并记录在案。......
  • struts2配置文件中的method={1}详解
    转载:fifiyong  https://www.cnblogs.com/fifiyong/p/6027565.htmlstruts.xml中的配置:<!--配置用户模块的action--><actionname="user_*"class="userAction"method="{1}"><resultname="registPage">/W......
  • 主从数据库同步配置详解(MySQL/MariaDB)
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、环境准备与安装配置本地部署MySQLUbuntu系统:CentOS系统:MariaDBUbuntu系统:CentOS系统:容器部署MySQLMariaDB二、配置主从库的同步设置四、测试与维护总结前言在数据库管理中,......
  • Stable Diffusion 使用详解(13)--- 3D纹理增强
    目录背景NormalMap描述原理使用心得例子描述原图参数设置底模​编辑正负相关性提示词其他参数controlnet效果还能做点啥调整效果背景实际上,在stablediffusion中,你获取发现很多controlnet其实功能有点类似,你都使用完一遍之后,会发现条条道路通罗马,有的......
  • 文件上传日志包含详解与CTF实战
    1.日志简介1.1日志介绍日志是记录系统或应用程序运行时事件的文件。这些记录可以包括错误信息、用户活动、系统性能指标等,帮助开发者和管理员监控和排查问题。日志通常会记录多种内容,包括:时间戳:事件发生的具体时间。用户代理(UA)头:浏览器或客户端的类型和版本。IP地址:发起......