Android 开发生僻却实用的知识点 Part 3:从二维码性能优化到 Mockito 测试实战
文档教程知识库【免费下载链接】android-tech-frontier【停止维护】一个定期翻译国外Android优质的技术、开源库、软件架构设计、测试等文章的开源项目项目地址https://gitcode.com/gh_mirrors/an/android-tech-frontier点击查看免费下载导读本文是Android 开发生僻却实用的知识点系列文章的第三部分由 WillowTree 团队的 Android 开发者们分享他们在实际项目中踩过的坑与积累的小技巧。文章覆盖七个实战知识点ZXing 二维码大图生成性能优化、adb命令的小细节、TextUtils.concat()的正确使用、父 View 与子 View 的触摸事件拦截博弈、SQLite 事务的提交/回滚陷阱、单元测试中的静态方法限制以及用 Mockito 简化对象依赖的实践。读完本文你将获得可直接复制进工程的高效二维码生成方案、更稳妥的事务与事件分发处理方式以及一套更清爽的测试代码写法。如果你是第一次阅读本系列可以先看看团队在 Part 1Android Studio Image Asset、StrictMode、adjustResize 等和 Part 2WebView 崩溃、RecyclerView position、Collections.emptyList()等中分享的内容。本文在仓库中的位置是 issue-31/Android开发生僻却实用的知识点Part3.md。Tidbit One用 ZXing 高效生成大尺寸二维码如果你正在使用 ZXing 的二维码生成器库来生成二维码会发现直接用它生成大图片比较慢。QRCodeWriter.encode()在指定大尺寸时需要对整个矩阵做逐位填充与渲染尺寸越大耗时越长。核心思路先生成最小矩阵再按需缩放一个被验证可行的优化办法是向库传入0 x 0的图片尺寸此时它会返回一个最小尺寸的BitMatrix矩阵中每一个块对应 1 像素。之后你把这个小矩阵写入BitmapDrawable再将其设为某个 View 的背景由 View 的绘制系统按需缩放展示——这样就把生成大图的昂贵工作替换成了生成小图 缩放的廉价操作。BitMatrix matrix new QRCodeWriter() .encode(content here, BarcodeFormat.QR_CODE, 0, 0); int height matrix.getHeight(); int width matrix.getWidth(); Bitmap bmp Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); for (int x 0; x width; x) { for (int y 0; y height; y) { bmp.setPixel(x, y, matrix.get(x, y) ? Color.BLACK : Color.TRANSPARENT); } } BitmapDrawable qrCodeDrawable new BitmapDrawable(getResources(), bmp); qrCodeDrawable.setFilterBitmap(false); // 关键防止缩放时模糊 imgQrCode.setBackground(qrCodeDrawable);三个关键注意点必须调用setFilterBitmap(false)如果不关闭位图过滤BitmapDrawable在放大显示时会被插值平滑导致二维码的黑白边缘发灰、变得模糊最终影响扫码识别率。所以在把 Drawable 设进 View 之前务必先执行qrCodeDrawable.setFilterBitmap(false)。按需选择位图格式原文示例因二维码背景需要透明使用了Bitmap.Config.ARGB_4444。如果只想要黑白两色、不需要透明背景可以用Bitmap.Config.RGB_565内存占用更小。需要提醒的是ARGB_4444从 API 16 开始已被官方标记为不推荐使用deprecated在新项目里建议优先评估RGB_565或直接采用下面的稳妥方案。对0 x 0参数的兼容性要保持警惕库的实现可能在未来版本中不再接受0 x 0这种非常规参数——毕竟二维码的符号结构决定了其最小尺寸也不可能比10 x 10更小。如果你担心升级库后出现兼容问题可以把创建方法改为显式指定一个较小的尺寸BitMatrix matrix new QRCodeWriter() .encode(content here, BarcodeFormat.QR_CODE, 10, 10);源码层面的依据上述 API 行为直接来自 ZXing 的QRCodeWriter与BitMatrix定义encode(contents, format, width, height)返回用于描述二维码明暗块的矩阵对象matrix.get(x, y)在坐标为true时表示该块为黑色而BitmapDrawable的setFilterBitmap(boolean)正是控制缩放时是否进行双线性过滤的开关。这套小矩阵 关闭过滤 View 背景缩放的组合拳是二维码从生成慢到秒出图的关键。Tidbit Twoadb hell与adb shell结果相同一个看起来匪夷所思、实测却真实存在的小现象在命令行输入adb hell和输入adb shell得到的结果是一样的——adb会进入设备上的 shell 交互环境。这个知识点更多是一个有趣的观察记录adb工具在解析子命令时存在一定的容错行为因此拼写错误这里是缺少s的hell也可能被温柔地接受。不过必须强调两点不要在脚本或 CI 流程中依赖这种容错行为它是未文档化的实现细节任何版本的adb工具更新都可能收紧参数解析规则让这个特性失效日常开发请始终书写完整、正确的命令adb shell避免在自动化场景中埋下不确定性。Tidbit Three用TextUtils.concat()优雅地拼接 CharSequenceTextUtils.concat()是 Android 框架层提供的字符串拼接工具它能把传入的多个CharSequence连接在一起同时保留它们各自的间距Spannable 等格式信息并且返回值仍然是一个CharSequence。这一点和普通的字符串拼接有本质区别a b会把内容降级为纯String若源文本携带Spannable字体、颜色、下划线等富文本样式拼接过程会丢失这些样式TextUtils.concat()则保留原CharSequence中的格式数据适合在需要动态组装富文本如用户名 时间 正文混合展示的场景使用。用法示意CharSequence result TextUtils.concat(title, - , timestamp, - , body);它的返回值仍是CharSequence可以直接传给TextView.setText()或继续参与后续的字符串处理流程是处理富文本拼接时一个值得记住的 API。Tidbit Four父 View 拦截与子 View 的反拦截在 Android 的触摸事件分发机制中子 View 处理的点击事件通常都是由父 View 先拦截、再分发下来的事件从ViewGroup的dispatchTouchEvent()进入经onInterceptTouchEvent()决定是否拦截最终才到达目标子 View。因此如果你需要使用某个子 View 正在处理的点击事件正确做法是使用父 View 的拦截事件方法onInterceptTouchEvent()返回true。但这里存在一个博弈点子 View 可以通过调用requestDisallowInterceptTouchEvent(true)来禁止父 View 拦截自己正在处理的事件序列。如果父 View 出于业务需要必须在这种被禁止的情况下仍然拦截那唯一的办法就是重载requestDisallowInterceptTouchEvent()这个方法本身Override public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { // 忽略子 View 的请求强制保留父 View 的拦截能力 // super.requestDisallowInterceptTouchEvent(false); }简单总结这套关系子 View 想守住自己的事件 → 调用requestDisallowInterceptTouchEvent(true)父 View 想夺回事件的拦截权 → 重写requestDisallowInterceptTouchEvent()不把请求上交给默认实现。这在实现嵌套滚动如列表嵌套、滑动冲突处理时是绕不开的必修课。Tidbit FiveSQLite 事务的提交/回滚陷阱在执行批量写入等耗时操作时调用SQLiteDatabase的beginTransaction()与endTransaction()能显著提升性能减少磁盘 I/O 次数。但这里有一个极易踩中的坑必须调用setTransactionSuccessful()事务的完整流程是db.beginTransaction(); try { // 批量 insert / update / delete 操作 db.setTransactionSuccessful(); // 标记事务成功 } finally { db.endTransaction(); // 根据标记决定 commit 或 rollback }endTransaction()并不会盲目提交它依据的是此前是否调用了setTransactionSuccessful()。如果你忘了这一行那么在调用endTransaction()时本次事务内做出的所有修改都会被回滚——数据库文件看起来一切正常但数据实际一条都没写进去这种静默失败往往比直接报错更难排查。因此请记住这条铁律beginTransaction()之后、endTransaction()之前务必在业务代码正常执行的路径上调用setTransactionSuccessful()并配合try/finally保证异常情况下也能正确结束事务。Tidbit Six单元测试中的静态方法陷阱如果你正在为应用添加测试用例千万要小心静态方法Android 框架层提供的很多方法在测试单元里根本不能用——它们依赖真实的系统服务、Binder 或底层 native 实现在 JVM 单元测试无设备环境下无法正常执行更麻烦的是由于它们是静态方法你甚至不能用 Mockito 之类的框架去模拟它们——Mockito 基于动态代理/子类化实现 mock只能处理可继承、可覆写的实例方法静态方法是它的盲区。这导致一个常见现象业务代码一旦在关键路径上调用了静态的框架方法如System.currentTimeMillis()、TextUtils.isEmpty()等测试代码就会变得难以编写和控制。应对思路包括在设计上尽量把静态调用包进可 mock 的实例对象依赖注入一个时钟或文本工具包装类必要时引入支持静态方法 mock 的专用框架如 PowerMock 家族但要注意它自身的兼容性与维护成本。结合本仓库中的测试主题文章可见这个约束正是推动面向接口编程 依赖注入的重要动机之一可测试性往往倒逼出更好的代码结构。Tidbit Seven用 Mockito 简化测试中的对象依赖与 Tidbit Six 配套的正面建议是试试 Mockito。它为你在测试用例中创建、配置和验证对象行为提供了简洁的 API能大大简化之前那些测试用例中复杂的对象依赖——不再需要手写一堆 Fake 或 Stub 类只需用mock()、when()、verify()等调用即可完成替身对象的装配。本仓库恰好收录了两篇可直接对照学习的实践文章使用Mockito对异步方法进行单元测试演示了用doAnswer()同步触发回调、以及用ArgumentCaptor捕获回调参数再手动驱动异步逻辑的两种测试方案解决异步函数不好测的经典难题doAnswer(new Answer() { Override public Object answer(InvocationOnMock invocation) throws Throwable { ((DummyCallback) invocation.getArguments()[0]).onSuccess(results); return null; } }).when(mockDummyCollaborator).doSomethingAsynchronously(any(DummyCallback.class)); // 然后正常调用被测方法并 verify 交互Android测试框架Dagger2Espresso2Mockito展示如何用Mockito.when(clock.getNow()).thenReturn(new DateTime(2008, 9, 23, 0, 0, 0))让测试日期不再依赖真实时钟从而断言 UI 显示为2008-09-23。这两个示例分别对应了 Mockito 在单元测试层和UI 测试层的典型用法可以作为你落地 Mockito 时的参考实现。小结本期的七个知识点看似零散实则覆盖了 Android 开发的几个高频痛点知识点核心要点ZXing 二维码用0 x 0生成最小矩阵 setFilterBitmap(false)按需缩放adb 命令adb hell与adb shell结果一致但不可依赖容错TextUtils.concat()保留 CharSequence 样式信息适合富文本拼接触摸事件子 View 用requestDisallowInterceptTouchEvent防拦截父 View 可重写该方法夺回控制权SQLite 事务忘记setTransactionSuccessful()会导致endTransaction()时全部回滚静态方法框架静态方法无法在单元测试中执行也无法 mock需借助设计规避Mockito用 mock/verify 大幅简化对象依赖仓库内有异步测试与 UI 测试两份实战参考这些技巧的共同价值在于它们都源自真实项目中的具体问题规模虽小却能在关键时刻帮你避开一类隐蔽的 Bug 或性能陷阱。更多同系列内容可继续阅读 Part 1 与 Part 2也欢迎翻阅 issue-31 目录下的其他译文依赖注入框架、RxJava 调试、应用架构等扩充你的 Android 知识图谱。赞分享文档教程知识库【免费下载链接】android-tech-frontier【停止维护】一个定期翻译国外Android优质的技术、开源库、软件架构设计、测试等文章的开源项目项目地址https://gitcode.com/gh_mirrors/an/android-tech-frontier点击查看免费下载相关推荐TexturePanner社区贡献指南如何为这个开源Shader项目做出贡献TexturePanner社区贡献指南如何为这个开源Shader项目做出贡献 TexturePanner是一个为Unity3D开发的开源Shader项目主要WeChatQRCode Android二维码识别库深度指南从入门到实战WeChatQRCode Android二维码识别库深度指南从入门到实战 WeChatQRCode是基于OpenCV开源的微信二维码引擎移植的Android扫移动开发计算机视觉Akagi雀魂AI助手5分钟搭建你的智能麻将教练Akagi雀魂AI助手5分钟搭建你的智能麻将教练 你是否在雀魂对局中常常感到迷茫面对复杂的牌局不知如何决策Akagi雀魂AI助手正是为你量身打造的智能麻将桌面应用人工智能上一篇Qwen3-30B-A3B-FP8中小企业大模型本地化部署的转折点下一篇nginx-module-vts高级特性流量限制、过滤器与实时控制完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

JVM内存核心解析:堆、堆外、GC调优与线上排查实战

JVM内存核心解析:堆、堆外、GC调优与线上排查实战

JDK自带的jmap -histo:live有时会把线上服务卡住,排查问题我用的是jhsdb jmap --histo --pid配合jstat做初步定位,高危场景优先用Arthas的memory命令在线查看,避免影响业务。1. 从一份真实崩溃报告讲起:JVM内存到底分了几块说个我…

2026/10/10 8:36:06 阅读更多 →
Python函数进阶:一等公民、闭包、装饰器与生成器全解析

Python函数进阶:一等公民、闭包、装饰器与生成器全解析

写函数的人很多,把函数写“通”的人不多。我一直觉得,Python里的函数是个特别有意思的话题——语法上十分钟就能学会,但真正能把函数用得行云流水、让代码既好读又好维护的人,却没那么常见。不少朋友写了几年Python,用…

2026/10/10 8:36:06 阅读更多 →
Redis List详解:底层结构、命令实战与性能优化指南

Redis List详解:底层结构、命令实战与性能优化指南

做后端这几年,凡是遇到“最新列表”“待处理队列”“消息排队”这类需求,我第一反应都是Redis的List。在Redis里,List就是一个按插入顺序排列的字符串链表,端点插入、弹出都是O(1),配合LRANGE做分页也很顺手&#xff0…

2026/10/11 13:06:44 阅读更多 →

最新新闻

油气管道SCADA系统:三代沿革、架构选型与数字管道落地实践

油气管道SCADA系统:三代沿革、架构选型与数字管道落地实践

简介:这份PPT面向油气储运、自动化及工业控制领域的学习者与工程技术人员,系统讲解油气管道SCADA系统及过程控制的核心知识,帮助读者建立从数据采集、监视控制到数字化管道建设的整体认知框架。资源为单个PPT文件,压缩包约5.29MB&…

2026/10/11 14:49:45 阅读更多 →
人形机器人运动控制入门:Xbotics运控全景从行走到全身操作

人形机器人运动控制入门:Xbotics运控全景从行走到全身操作

【免费下载链接】Xbotics-Embodied-Guide Xbotics 社区具身智能学习指南:我们把“具身综述→学习路线→仿真学习→开源实物→人物访谈→公司图谱”串起来,帮助新手和实战者快速定位路径、落地项目与参与开源。 项目地址: https://gitcode.com…

2026/10/11 14:49:45 阅读更多 →
基于AB 1756 PLC的冲渣池泵阀联锁控制与上位机画面整合实践

基于AB 1756 PLC的冲渣池泵阀联锁控制与上位机画面整合实践

说到钢铁厂里的冲渣池,很多搞自动化的人第一反应是工艺简单,不就是几台泵、几个阀、再配个液位嘛。可真到了现场你会发现,蒸汽弥漫、水温高、池面波动快,泵空转、水池溢流、阀后憋压,哪一件都不是小事。我最近完成了一…

2026/10/11 14:49:45 阅读更多 →
高校食堂点评系统实战:低样本下的评分排序与推荐算法

高校食堂点评系统实战:低样本下的评分排序与推荐算法

简介:这是一套面向高校学生与教职员工、基于PHP开发的食堂菜品点评Web应用源码,适合Web开发初学者、课程设计或毕业设计参考者,用于实现菜品打分、评论互动、食堂信息展示与数据分析等功能。压缩包共146个文件,约43.18MB&#xff…

2026/10/11 14:49:45 阅读更多 →
绝缘子缺陷识别数据集:COCO转YOLOv8训练实战与避坑指南

绝缘子缺陷识别数据集:COCO转YOLOv8训练实战与避坑指南

简介:面向电力巡检与视觉检测方向的开发者,这份绝缘子缺陷识别数据集提供1598张真实巡检图片,并完成COCO格式标注,可支持训练目标检测或实例分割模型,识别光盘损坏、绝缘子本体及污闪三类典型异常,标注正确…

2026/10/11 14:49:45 阅读更多 →
OpenClaw网关层架构解析:从请求生命周期到流量治理核心设计

OpenClaw网关层架构解析:从请求生命周期到流量治理核心设计

OpenClaw 拆完整个网关层之后,我发现真正决定线上稳定性的往往不是业务代码,而是流量进来之后的前 100 毫秒。这次写一篇 OpenClaw 技术架构解析-网关层(上),主要讲讲接入层的设计定位、核心组件拆解、一次完整请求的生…

2026/10/11 14:48:45 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →