最近有个需求,后端给出的图片地址并不是正常的 URL,而且需要一个接口去请求,但是返回的是 base64 数据流。这里不关心为啥要这么多,原因有很多,可能是系统的问题,也可能是能力问题。当然作为我们 Android 程序员,要紧的是如何解决这个问题。

首先我们拿到接口链接,我这次拿到的是这样的:

https://www.example.com/cdn/attach/{fileId}/base64

这里的{fileId} 是指图片的 id,那么正常的图片地址可以理解为:

https://www.example.com/cdn/attach/1000/base64
https://www.example.com/cdn/attach/1002/base64

熟悉 Glide 加载逻辑的人,应该很熟悉,这种方式可能需要我们自定义ModelLoader 来解决问题,们可以让 Glide 将 API 接口当作一种图片源来处理,就像处理普通的图片 URL 一样。

实现方案

我们可以自定义 Base64ApiModelLoader 来处理 base64 的请求数据:

public class Base64ApiModelLoader implements ModelLoader<String, InputStream> {private static final String BASE_URL = "https://your-api-base-url/";private static final String API_PATH = "cdn/attach/";private final OkHttpClient okHttpClient;public Base64ApiModelLoader() {this.okHttpClient = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS).readTimeout(15, TimeUnit.SECONDS).build();}@Nullable@Overridepublic LoadData<InputStream> buildLoadData(@NonNull String fileId, int width, int height, @NonNull Options options) {// 创建缓存键,使用文件ID作为唯一标识Key key = new ObjectKey(API_PATH + fileId);// 返回加载数据,包含缓存键和数据获取器return new LoadData<>(key, new Base64ApiFetcher(fileId, okHttpClient));}@Overridepublic boolean handles(@NonNull String model) {// 判断是否是文件ID格式,这里简单判断不是URLreturn !model.startsWith("http") && !model.startsWith("data:");}// 工厂类,用于创建ModelLoaderpublic static class Factory implements ModelLoaderFactory<String, InputStream> {@NonNull@Overridepublic ModelLoader<String, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {return new Base64ApiModelLoader();}@Overridepublic void teardown() {// 清理资源}}// 数据获取器,负责从API获取Base64数据并转换为InputStreamprivate static class Base64ApiFetcher implements DataFetcher<InputStream> {private final String fileId;private final OkHttpClient okHttpClient;private InputStream inputStream;private volatile boolean isCancelled;Base64ApiFetcher(String fileId, OkHttpClient okHttpClient) {this.fileId = fileId;this.okHttpClient = okHttpClient;}@Overridepublic void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {if (isCancelled) {callback.onLoadFailed(new IOException("Cancelled"));return;}// 构建API请求URLString apiUrl = BASE_URL + API_PATH + fileId + "/base64";Request request = new Request.Builder().url(apiUrl).build();try {// 执行请求Response response = okHttpClient.newCall(request).execute();if (!response.isSuccessful()) {callback.onLoadFailed(new IOException("Failed to load Base64 data: " + response.code()));return;}// 解析响应体ResponseBody responseBody = response.body();if (responseBody == null) {callback.onLoadFailed(new IOException("Empty response"));return;}// 解析JSON响应String jsonString = responseBody.string();JSONObject jsonObject = new JSONObject(jsonString);// 检查响应码int code = jsonObject.optInt("code", -1);if (code != 200) {callback.onLoadFailed(new IOException("API error: " + jsonObject.optString("message", "Unknown error")));return;}// 获取Base64数据String base64Data = jsonObject.optString("data", "");if (base64Data.isEmpty()) {callback.onLoadFailed(new IOException("Empty Base64 data"));return;}// 处理可能存在的Data URI前缀if (base64Data.contains(",")) {base64Data = base64Data.split(",")[1];}// 解码Base64数据byte[] imageBytes = Base64.decode(base64Data, Base64.DEFAULT);// 创建输入流inputStream = new ByteArrayInputStream(imageBytes);// 回调成功callback.onDataReady(inputStream);} catch (IOException | JSONException | IllegalArgumentException e) {if (!isCancelled) {callback.onLoadFailed(e);}}}@Overridepublic void cleanup() {if (inputStream != null) {try {inputStream.close();} catch (IOException ignored) {// 忽略关闭错误}}}@Overridepublic void cancel() {isCancelled = true;}@NonNull@Overridepublic Class<InputStream> getDataClass() {return InputStream.class;}@NonNull@Overridepublic DataSource getDataSource() {return DataSource.REMOTE;}}
}

定义完成ModelLoader之后,我们可能就要注册ModelLoader了。


@GlideModule
public class MyAppGlideModule extends AppGlideModule {@Overridepublic void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {super.registerComponents(context, glide, registry);// 注册我们的自定义ModelLoader,用于处理Base64 API请求registry.append(String.class, InputStream.class, new Base64ApiModelLoader.Factory());}@Overridepublic boolean isManifestParsingEnabled() {return false;}
}

当然不能忘记需要有注解处理器

annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1'

处理完之后,我们就可以这么调用了:

		Glide.with(imageView.getContext()).load(fileId)  // +.placeholder(R.mipmap.default_image).error(R.mipmap.default_image).into(imageView);

我们之前 load 方法中一直调用的是 url, 这里就直接调用 fileId 即可。因为我们已经定义了

registry.append(String.class, InputStream.class, new Base64ApiModelLoader.Factory());

其他地方都不变,即可正常进行请求了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/904279.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/904279.shtml
英文地址,请注明出处:http://en.pswp.cn/news/904279.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

004-nlohmann/json 快速认识-C++开源库108杰

了解 nlohmann/json 的特点&#xff1b;理解编程中 “数据战场”划分的概念&#xff1b;迅速上手多种方式构建一个JSON对象&#xff1b; 1 特点与安装 nlohmann/json 是一个在 github 长期霸占 “JSON” 热搜版第1的CJSON处理库。它的最大优点是与 C 标准库的容器数据&#xf…

#基础Machine Learning 算法(上)

机器学习算法的分类 机器学习算法大致可以分为三类&#xff1a; 监督学习算法 (Supervised Algorithms&#xff09;:在监督学习训练过程中&#xff0c;可以由训练数据集学到或建立一个模式&#xff08;函数 / learning model&#xff09;&#xff0c;并依此模式推测新的实例。…

正弦波、方波、三角波和锯齿波信号发生器——Multisim电路仿真

目录 Multisim使用教程说明链接 一、正弦波信号发生电路 1.1正弦波发生电路 电路组成 工作原理 振荡频率 1.2 正弦波发生电路仿真分析 工程文件链接 二、方波信号发生电路 2.1 方波发生电路可调频率 工作原理 详细过程 2.2 方波发生电路可调频率/可调占空比 调节占空比 方波产生…

【AND-OR-~OR锁存器设计】2022-8-31

缘由锁存器11111111111-硬件开发-CSDN问答 重置1&#xff0c;不论输入什么&#xff0c;输出都为0&#xff1b; 重置0&#xff0c;输入1就锁住1 此时输入再次变为0&#xff0c;输出不变&#xff0c;为锁住。

力扣-字符串-468 检查ip

思路 考察字符串的使用&#xff0c;还有对所有边界条件的检查 spilt&#xff08;“\.”&#xff09;&#xff0c;toCharArray&#xff0c;Integer.parseInt() 代码 class Solution {boolean checkIpv4Segment(String str){if(str.length() 0 || str.length() > 4) retur…

BC8 十六进制转十进制

题目&#xff1a;BC8 十六进制转十进制 描述 BoBo写了一个十六进制整数ABCDEF&#xff0c;他问KiKi对应的十进制整数是多少。 输入描述&#xff1a; 无 输出描述&#xff1a; 十六进制整数ABCDEF对应的十进制整数&#xff0c;所占域宽为15。 备注&#xff1a; printf可以使用…

ARM子程序和栈

微处理器中的栈由栈指针指向存储器中的栈顶来实现&#xff0c;当数据项入栈时&#xff0c;栈 指针向上移动&#xff0c;当数据项出栈时&#xff0c;栈指针向下移动。 实现栈时需要做出两个决定&#xff1a;一是当数据项进栈时是向低位地址方向向上生 长&#xff08;图a和图b&a…

jwt身份验证和基本的利用方式

前言 &#xff1a; 什么是jwt&#xff08;json web token&#xff09;&#xff1f; 看看英文单词的意思就是 json形式的token 他的基本的特征 &#xff1a; 类似于这样的 他有2个点 分割 解码的时候会有三个部分 头部 payload 对称密钥 这个就是对称加密 头部&am…

n8n工作流自动化平台的实操:利用本地嵌入模型,完成文件内容的向量化及入库

1.成果展示 1.1n8n的工作流 牵涉节点&#xff1a;FTP、Code、Milvus Vector Store、Embeddings OpenAI、Default Data Loader、Recursive Character Text Splitter 12.向量库的结果 2.实操过程 2.1发布本地嵌入模型服务 将bge-m3嵌入模型&#xff0c;发布成满足open api接口…

MATLAB人工大猩猩部队GTO优化CNN-LSTM多变量时间序列预测

本博客来源于CSDN机器鱼&#xff0c;未同意任何人转载。 更多内容&#xff0c;欢迎点击本专栏目录&#xff0c;查看更多内容。 目录 0 引言 1 数据准备 2 CNN-LSTM模型搭建 3 GTO超参数优化 3.1 GTO函数极值寻优 3.2 GTO优化CNN-LSTM超参数 3.3 主程序 4 结语 0 引言…

git项目迁移,包括所有的提交记录和分支 gitlab迁移到gitblit

之前git都是全新项目上传&#xff0c;没有迁移过&#xff0c;因为迁移的话要考虑已有项目上的分支都要迁移过去&#xff0c;提交记录能迁移就好&#xff1b;分支如果按照全新项目上传的方式需要新git手动创建好老git已有分支&#xff0c;在手动一个一个克隆老项目分支代码依次提…

Photo-SLAM论文理解、环境搭建、代码理解与实测效果

前言&#xff1a;第一个解耦式Photo-SLAM&#xff0c;亮点和效果。 参考&#xff1a;https://zhuanlan.zhihu.com/p/715311759 全网最细PhotoSLAM的conda环境配置教程&#xff0c;拒绝环境污染&#xff01;&#xff01;-CSDN博客 1. 环境搭建 硬件&#xff1a;RTX 4090D wi…

如何使用VSCode编写C、C++和Python程序

一、首先准备好前期工作。如下载安装Python、VSCode、一些插件等。写代码之前需要先创建文件夹和文件。 二、将不同语言写的代码放在不同的文件夹中&#xff0c;注意命名时不要使用中文。 三、打开VSCode&#xff0c;点击“文件”->“打开文件夹”->“daimalainxi”->…

基于不确定性感知学习的单图像自监督3D人体网格重建 (论文笔记与思考)

文章目录 论文解决的问题提出的算法以及启发点 论文解决的问题 首先这是 Self-Supervised 3D Human mesh recovery from a single image with uncertainty-aware learning &#xff08;AAAI 2024&#xff09;的论文笔记。该文中主要提出了一个自监督的framework用于人体的姿态…

Leetcode刷题记录33——二叉树的最小深度

题源&#xff1a;https://leetcode.cn/problems/minimum-depth-of-binary-tree/description/ 题目描述&#xff1a; 思路一&#xff1a; 使用 DFS 递归遍历的解法&#xff0c;每当遍历到一条树枝的叶子节点&#xff0c;就会更新最小深度&#xff0c;当遍历完整棵树后&#x…

有效的括号(20)

20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a; class Solution { public:bool isValid(string s) {unordered_map<char, char> m {{), (}, {],[}, {}, {}};stack<char> stk;for (int i 0; i < s.size(); i) {if (s[i] ( || s[i…

电子邮件相关协议介绍

0 Preface/Foreword 1 协议介绍 电子邮件包含的主要协议&#xff1a; SMTPPOPIMAP 1.1 SMPT SMPT: Simple Mail Transfer Protocol&#xff0c;电子邮件传输的标准协议&#xff0c;负责将邮件从发送方传输到接收方邮件服务器。 1.2 POP POP&#xff1a; Post Office Protoc…

Linux压缩和解压类

一、gzip/gunzip 压缩 1、基本语法 gzip 文件 &#xff08;功能描述&#xff1a;压缩文件&#xff0c;只能将文件压缩为*.gz文件&#xff09; gunzip 文件.gz &#xff08;功能描述&#xff1a;解压缩文件命令&#xff09; 2、经验技巧 &#xff08;1&#…

力扣hot100 (除自身以外数组的乘积)

238. 除自身以外数组的乘积 中等 给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除…

什么是“系统调用”

一、什么是“系统调用”&#xff1f;用生活中的比喻理解 可以把“系统调用”比作你&#xff08;用户&#xff09;向“管理员”请求帮助完成某件事情的过程。 举个例子&#xff1a; 你想借书&#xff0c;去图书馆&#xff08;操作系统&#xff09;找管理员&#xff08;内核&a…