拦截器在Android网络中的运用技巧

2023-12-05

在这里插入图片描述

当涉及到Android应用程序中的网络请求处理时,OkHttp是一个非常强大和流行的工具。其中一个关键的功能是拦截器(Interceptors),它们允许您在请求和响应传输到 服务器 和应用程序之间执行各种操作。在本文中,我们将深入研究OkHttp拦截器,了解其工作原理以及如何使用它们来优化您的Android应用程序。

什么是OkHttp拦截器

OkHttp拦截器是一种机制,允许您在网络请求和响应的传输过程中执行自定义操作。它们通常用于记录请求日志、修改请求头、缓存响应或进行 身份验证 等操作。拦截器可以按照添加它们的顺序依次执行,从而形成一个拦截器链。

拦截器链

拦截器链是一个由多个拦截器组成的链条,每个拦截器在请求和响应的传输过程中都有机会进行操作。这些拦截器按照它们添加的顺序执行,因此顺序很重要。以下是一个拦截器链的示意图:

Request 1 -> Interceptor 1 -> Interceptor 2 -> ... -> Interceptor N -> Server
                            <-                <- ... <-                <-
Response 1 <- Interceptor 1 <- Interceptor 2 <- ... <- Interceptor N <- Server

OkHttp中拦截器的工作原理

OkHttp的核心组件是 Interceptor 接口和 RealCall 类。 Interceptor 接口定义了 intercept() 方法,它接收一个 Chain 对象作为参数,该对象用于执行拦截器链上的操作。 RealCall 类用于实际执行网络请求并管理拦截器链的执行。

创建OkHttpClient

首先,您需要创建一个 OkHttpClient 实例,该实例用于发起网络请求,并配置拦截器链。

OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new CustomInterceptor())
    .build();
发起网络请求

当您调用 client.newCall(request) 来创建一个新的网络请求时,OkHttp会创建一个 RealCall 对象,该对象代表了实际的网络请求。接下来, RealCall 会执行拦截器链上的操作。

Request request = new Request.Builder()
    .url("https://example.com/api")
    .build();

Call call = client.newCall(request);
Response response = call.execute();
拦截器链执行

拦截器链的执行是在 RealCall 类中完成的,它遍历拦截器列表并按照添加顺序依次执行。以下是相关源码示例:

public Response getResponseWithInterceptorChain() throws IOException {
    // 创建一个初始的Interceptor.Chain
    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));
    interceptors.add(new CallServerInterceptor(false));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, 0, originalRequest, this, callStackTrace);

    // 依次执行拦截器
    return chain.proceed(originalRequest);
}
Interceptor.Chain的实现

RealInterceptorChain 类实现了 Interceptor.Chain 接口,它包含了当前请求的信息,并负责执行拦截器链上的操作。在 proceed() 方法中,它依次调用拦截器的 intercept() 方法,将请求传递给下一个拦截器,并最终返回响应。

public Response proceed(Request request) throws IOException {
    // 执行下一个拦截器或者发起网络请求
    if (index >= interceptors.size()) throw new AssertionError();
    calls++;
    if (chain == null) throw new IllegalStateException("Check failed.");
    if (eventListener != null) {
        eventListener.callStart(this);
    }

    // 获取当前拦截器
    Interceptor interceptor = interceptors.get(index++);

    // 调用拦截器的intercept方法,将请求传递给下一个拦截器或者执行网络请求
    Response response = interceptor.intercept(this);

    if (eventListener != null) {
        eventListener.callEnd(this);
    }

    return response;
}

编写自定义拦截器

要编写自定义拦截器,首先需要实现 Interceptor 接口,并实现 intercept() 方法。这个方法接收一个 Chain 对象作为参数,允许您访问和操作请求和响应。

public class CustomInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        // 在请求前执行的代码
        Request originalRequest = chain.request();
        
        // 可以修改请求
        Request modifiedRequest = originalRequest.newBuilder()
                .addHeader("Authorization", "Bearer YourAccessToken")
                .build();
        
        // 执行请求
        Response response = chain.proceed(modifiedRequest);
        
        // 在响应后执行的代码
        // 可以修改响应
        
        return response;
    }
}

实际应用示例

以下是一些实际运用示例,展示了如何使用OkHttp拦截器来实现不同的功能

日志记录

这个拦截器用于记录请求和响应的详细信息,有助于调试和排查问题。

public class LoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        long startTime = System.nanoTime();
        Log.d("OkHttp", String.format("Sending request %s on %s%n%s",
            request.url(), chain.connection(), request.headers()));
        
        Response response = chain.proceed(request);
        
        long endTime = System.nanoTime();
        Log.d("OkHttp", String.format("Received response for %s in %.1fms%n%s",
            response.request().url(), (endTime - startTime) / 1e6d, response.headers()));
        
        return response;
    }
}
身份验证

这个拦截器用于在每个请求中添加身份验证标头,以确保请求是经过身份验证的。

public class AuthInterceptor implements Interceptor {
    private final String authToken;

    public AuthInterceptor(String authToken) {
        this.authToken = authToken;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        
        // 添加身份验证标头
        Request authenticatedRequest = originalRequest.newBuilder()
                .header("Authorization", "Bearer " + authToken)
                .build();
        
        return chain.proceed(authenticatedRequest);
    }
}
缓存

这个拦截器用于实现响应缓存,以减少对服务器的请求。

public class CacheInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        
        // 在这里检查是否有缓存可用,如果有,返回缓存的响应
        
        Response response = chain.proceed(request);
        
        // 在这里将响应缓存起来
        
        return response;
    }
}
请求重试

这个拦截器用于处理请求失败时的重试逻辑。

public class RetryInterceptor implements Interceptor {
    private final int maxRetryCount;

    public RetryInterceptor(int maxRetryCount) {
        this.maxRetryCount = maxRetryCount;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = null;
        IOException lastException = null;

        for (int retryCount = 0; retryCount < maxRetryCount; retryCount++) {
            try {
                response = chain.proceed(request);
                if (response.isSuccessful()) {
                    return response;
                }
            } catch (IOException e) {
                lastException = e;
            }
        }

        // 如果达到最大重试次数仍然失败,抛出异常
        throw lastException;
    }
}
自定义响应处理

这个拦截器用于在接收到响应后执行自定义的响应处理逻辑。

public class ResponseProcessingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        
        // 在这里对响应进行自定义处理
        
        return response;
    }
}
错误处理

这个拦截器用于处理一些常见的错误情况

public class ErrorHandlingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        try {
            Response response = chain.proceed(request);
            
            // 检查响应是否成功
            if (!response.isSuccessful()) {
                // 在这里处理错误,可以抛出自定义异常
                throw new MyHttpException(response.code(), response.message());
            }
            
            return response;
        } catch (IOException e) {
            // 在这里处理网络连接错误
            throw new MyNetworkException(e.getMessage(), e);
        }
    }
}
重定向请求

这个拦截器用于自定义重定向行为

public class RedirectInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        
        // 检查是否是重定向响应
        if (response.isRedirect()) {
            String newUrl = response.header("Location");
            if (newUrl != null) {
                // 构建新的请求并继续
                Request newRequest = request.newBuilder()
                        .url(newUrl)
                        .build();
                response = chain.proceed(newRequest);
            }
        }
        
        return response;
    }
}

结论

OkHttp拦截器是Android应用程序中处理网络请求的有力工具。通过创建自定义拦截器,您可以在请求和响应的传输过程中执行各种操作,以优化您的应用程序。无论是日志记录、身份验证、缓存还是其他操作,拦截器都可以帮助您更好地控制和定制网络请求流程。

最后大家分享一份全套的Android学习资料,给那些想学习 Android 的小伙伴们一点帮助!

适用于:

  • 任何想学习Android开发但不知道从哪里开始的人
  • 也适用于已经开始进行Android开发但想要变得更好的任何人

一、Android所有方向的学习路线

为了成为更好的 Android 开发者,这里为大家提供了总的路线图。它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。如果下面这个学习路线能帮助大家成为一个更好的 Android 开发者,那么我的使命也就完成了:

包括:Android应用开发、系统开发、音视频开发、Flutter开发、小程序开发、UI界面、车载系统开发等等

在这里插入图片描述

二、学习软件

工欲善其事必先利其器。学习Android常用的Android Studio视频教程和Android Studio最新的安装包都在这里了,给大家节省了很多时间。


三、进阶学习视频

我们在学习的时候,往往书籍源码难以理解,阅读困难,这时候视频教程教程是就很适合了,生动形象加上案例实战,科学有趣才能更方便的学习下去。

在这里插入图片描述

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

五、经典书籍阅读

阅读Android经典书籍可以帮助读者提高技术水平,开拓视野,掌握核心技术,提高解决问题的能力,同时也可以借鉴他人的经验。对于想要深入学习Android开发的读者来说,阅读Android经典书籍是非常有必要的。

在这里插入图片描述

六、面试资料

我们学习Android必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

图片

请添加图片描述

这份完整版的Android全套学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【 保证100%免费
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

拦截器在Android网络中的运用技巧 的相关文章

  • 带有垂直选项卡的 Android 布局 - 设计类似于 hello 短信应用程序

    Can somebody please help me out in designing vertical tabs like in the given pic taken from hello sms app 我不要求提供代码片段 所以请
  • Android Studio Profiler 中显示“无可调试进程”

    当我尝试在 Android Studio 中使用探查器时 我能够看到已连接的设备 但在探查器中收到 无可调试进程 有人可以帮助我为什么我收到 不可调试的进程 吗 您可以尝试以下任意 全部操作 使缓存失效并重新启动Android Studio
  • 旋转对话框的自定义主题

    我想自定义当我单击 spinnermode dialog 中的微调器时出现的对话框的外观 我想使用对话框片段 但没有找到文档 是否可以 不会 外观是固定的 给人一种操作系统的感觉 您必须创建自己的微调器才能执行此操作 这并不容易 但如果微调
  • 字符串生成器最大长度

    我想知道字符串生成器 或字符串缓冲区 的最大容量是多少 我的 Android 应用程序中有一个静态变量 它应该保存日志字符串 它最多可以容纳 130 行和大约 10000 个字符 我如果我附加更多内容 但它只是不显示 没有错误 没有例外 所
  • 如何调试使用maven构建的android应用程序

    我目前正在尝试从 Eclipse 调试我的设备上的 Android 应用程序 设备已添加 我可以在控制台和 Eclipse 中看到它 控制台 Windows adb devices List of devices attached 0019
  • Eddystone Beacon 中广播的 MAC ID 会改变吗?

    我将描述我的设置 我制作了一个模拟 Eddystone 信标的 Android 应用程序 我能够使用 PlayStore 中的 Beacon Toy 应用程序检测手机上的 Eddystone 信标 但问题是 自上次检查以来 显示的 MAC
  • 如何在谷歌地图中使用latlng字符串数组绘制多边形

    在我的应用程序中 我有包含 imagview 的 recyclerview 并且该 imageview 通过使用我存储在 sqlite 中的坐标包含静态地图图像 当我单击该图像时 我将该字符串数组格式的坐标传递给其他地图活动 然后使用该字符
  • 旧 Android SDK 版本上的 java.lang.NoClassDefFoundError

    我在 Google Play 上发布了我的应用程序的一个版本 今天早上醒来时发现了一些不满意的客户 该应用程序的最新版本集成了对蓝牙低功耗 BTLE 心率监测器的支持 该应用程序在 Android 4 3 和 4 4 上运行良好 但在 4
  • 应用程序可能在其主线程上做了太多工作 - Android

    您好 我正在开发一个 Android 应用程序 当我尝试从我的应用程序发送电子邮件时遇到此错误 我在后台发送邮件而不使用基于意图这个链接 http www oodlestechnologies com blogs Send Mail in
  • 在android中点击地图获取坐标

    我正在尝试做这样的事情 我有一个地图活动 当用户点击地图时 它会显示该位置的坐标 我已经重写了 onclick 方法 但它甚至没有被调用 任何想法 public class MapPoint extends MapActivity impl
  • 如何删除旧版本的Android Studio

    我必须释放硬盘中的一些空间 并寻找要删除的内容 我发现我有许多引用旧版本的 Android Studio AS 文件夹 我发现文件夹的路径是 C Users mysuername 我想要的是删除旧版本并只保留最新版本的方法 当时是 ASPr
  • Kotlin + Room:java.lang.IllegalArgumentException:void 无法转换为元素

    我试图在我的 Java Kotlin 项目中添加 Room 但是当我尝试编译该项目时 它失败了 app kaptDebugKotlin出现以下错误 e java lang IllegalStateException failed to an
  • 某些设备上的启动画面扭曲

    我在修复 Android 上的启动画面扭曲问题时遇到问题 我正在使用 React Native 请注意 这种情况仅发生在某些设备上 例如 我有一台 Android 版本为 4 2 2 的三星 启动画面不扭曲 而 Android 版本为 8
  • 使用 Android Exoplayer 调整 Dash 流音量

    我正在尝试设置一个搜索栏来控制 exoplayer 流式破折号实例的级别 我正在使用的设置是演示项目的修改版本 并且无法确定我应该尝试影响搜索栏输出的哪个元素 即如何正确使用 MSG SET VOLUME 等 任何意见将不胜感激 我正在寻找
  • 如何停止抖动中的计时器?

    我在 flutter 中创建了一个计时器 一切正常 现在我不知道如何在启动计时器后关闭它 文档说你可以通过调用取消它void cancel 但我不明白其实现 我该怎么称呼它 这是正确的方法吗 static const timeout con
  • 将 XML 从网站解析到 Android 设备

    我正在启动一个 Android 应用程序 它将解析来自网络的 XML 我创建了一些 Android 应用程序 但它们从未涉及解析 XML 我想知道是否有人对最佳方法有任何建议 这是一个例子 try URL url new URL your
  • Osmdroid:如何从我自己的位图(图块)创建和加载地图?

    我开始使用 Osmdroid 我想使用这项技术来显示有关 F1 赛道的地图 我有一张大图片 我可以将它切割成更小的图块 我可以修改osmdroid库来上传这些图片吗 我想将这些位图 图块 保存在我的资产文件夹中 我非常不知道如何做到这一点
  • IntelliJ 12 中的 Android Hello World - 找不到 android.app.Activity 类

    请看下文 我感觉 SDK 配置不正确 但我不知道如何解决 我尝试用谷歌搜索答案 但没有人遇到这个确切的问题 难道是我的Java版本不对 这两个 SDK 似乎可能相互冲突 我通过以下方式制作了这个项目 创建新项目 Android gt 应用模
  • 找出该月第一个星期日/星期一等的日期

    我想在java中检测每个月第一周 第二周的第一个星期日 星期一的日期 我怎样才能实现它 我已经检查了 java 中的 Calendar 类和 Date 类 但无法找到解决方案 所以请帮助我解决这个问题 Calendar calendar C
  • Android:如何获取所有可用意图过滤器的列表?

    我搜索了 Android 文档 但由于某些疯狂的原因 我无法找到所有可用意图过滤器的列表 我正在寻找一个意图过滤器 它可以执行诸如通过广播接收器通知我特定活动 例如浏览器或电子邮件 已启动或位于前台之类的操作 有人能帮我吗 PackageE

随机推荐