BigImageViewer 详解:模块化、可插拔引擎的大图查看库
上一篇聊了 SherlockGougou 的 BigImageViewPager,这篇来看名字相近、思路却不同的另一个库——Piasy/BigImageViewer。两者都解决"大图预览",但 BigImageViewer 更像一个"引擎中立"的底层组件:它以 Subsampling Scale ImageView(SSIV)为渲染内核,把图片加载能力做成可插拔适配器(Fresco / Glide),并用分块渲染把大图内存压到原来的零头。本文拆解它的核心思路、模块化架构、API 与使用边界。
1、项目概述
BigImageViewer 是 Piasy 开发的 Android 大图查看库,以 SSIV 为渲染内核,并外接可插拔的图片加载器。仓库约 4k Star,采用 MIT 协议,当前版本 1.8.1。它最大的卖点是:在支持平移、双指缩放的同时,把大图的内存占用压到极低。
典型场景:
- 长图、超大图详情页(漫画、地图、长截图)
- 对内存敏感、需展示多张高清图的页面
- 已有 Fresco 或 Glide 技术栈、想直接复用的项目
2、核心思路:SSIV 分块渲染规避 OOM
痛点在于:PhotoDraweeView、FrescoImageViewer 等方案在显示大图时内存暴涨,动辄 OOM。而 SSIV 虽然内存极省,却"只能显示本地文件"。BigImageViewer 正是来补上这一环。
关键对比:一张 4135×5134 的大图,竞品方案约占 80MB 内存,BigImageViewer 只需 2–20MB。
实现原理:
- SSIV 把大图切成 tile(瓦片),只把可见区域解码进内存
- 但 SSIV 本身只能加载本地文件,无法直接读网络图
- BigImageViewer 用图片加载器把网络图下到本地,再交给 SSIV 分块渲染
收益:既能加载网络大图,又能享受 SSIV 的低内存,把"低内存"和"网络加载"二者合一。
3、模块化架构与可插拔图片引擎
这是它与 BigImageViewPager 最大的区别:图片加载能力被抽象成 ImageLoader 接口,按需引入适配器,而不是绑死某一家框架。
模块划分:
- BigImageViewer:核心库,含 BigImageView 控件与 SSIV 集成
- FrescoImageLoader / GlideImageLoader:两种图片加载适配器
- FrescoImageViewFactory / GlideImageViewFactory:动图(gif / webp)支持
- ProgressPieIndicator:内置的下载进度饼形指示器
现状说明:
- 官方提供 Fresco 与 Glide 两种适配器,按已有技术栈二选一
- Picasso 适配器标记为 TODO、尚未实现;本仓库无 Coil 适配器
- 因此不必为了用它而更换图片框架
4、依赖与初始化
所有模块统一为 1.8.1 版本,托管在 mavenCentral。在模块的 build.gradle 中按需引入:
// 核心库(必选)
implementation 'com.github.piasy:BigImageViewer:1.8.1'
// 图片加载适配器:Fresco 与 Glide 二选一
implementation 'com.github.piasy:FrescoImageLoader:1.8.1'
implementation 'com.github.piasy:GlideImageLoader:1.8.1'
// 可选:下载进度指示器
implementation 'com.github.piasy:ProgressPieIndicator:1.8.1'
// 可选:动图(gif / webp)支持
implementation 'com.github.piasy:FrescoImageViewFactory:1.8.1'
implementation 'com.github.piasy:GlideImageViewFactory:1.8.1'然后在 Application 里用 ApplicationContext 初始化,传入所选适配器:
// 必须用 ApplicationContext,避免内存泄漏!
// 方式一:用 Fresco 加载
BigImageViewer.initialize(FrescoImageLoader.with(appContext));
// 方式二:用 Glide 加载
BigImageViewer.initialize(GlideImageLoader.with(appContext));接入要点:
1. repositories 中加入 mavenCentral,并尽量放在靠前位置
2. 引核心库 BigImageViewer,再按现有技术栈引入 FrescoImageLoader 或 GlideImageLoader
3. 动图、进度等能力按需引入对应可选模块
4. 初始化必须传 ApplicationContext,否则可能内存泄漏
5、显示图片、回调与进阶用法
核心方法是 showImage(注意不是 setImageURI)。最常见的是单图与"缩略图 + 原图"两种调用:
BigImageView bigImageView = findViewById(R.id.mBigImage);
// 仅显示原图
bigImageView.showImage(Uri.parse(url));
// 带缩略图:先显示低清缩略图,再过渡到原图
bigImageView.showImage(Uri.parse(thumbnail), Uri.parse(url));加载过程通过 ImageLoader.Callback 回调,覆盖缓存命中、下载进度与成功失败:
bigImageView.setImageLoaderCallback(new ImageLoader.Callback() {
@Override public void onCacheHit(int imageType, File image) { } // 命中缓存
@Override public void onCacheMiss(int imageType, File image) { } // 走网络下载
@Override public void onStart() { } // 开始下载
@Override public void onProgress(int progress) { } // 进度 0-100
@Override public void onFinish() { } // 下载结束
@Override public void onSuccess(File image) { } // 成功(缓存或网络)
@Override public void onFail(Exception error) { } // 失败
});进阶能力:
- 缩略图:showImage(thumbnail, origin) 先低清后高清,平滑过渡
- 进度指示:setProgressIndicator(new ProgressPieIndicator()),也可自定义
- 动图:setImageViewFactory(new GlideImageViewFactory()) 或 FrescoImageViewFactory()
- 保存相册:saveImageIntoGallery()(需自备权限、在 IO 线程调用)配合 setImageSaveCallback
- 预取:BigImageViewer.prefetch(uris) 提前下载,进入即显
- 失败重试:failureImage 占位图 + 点击重试;初始缩放类型可选 centerCrop / fitCenter 等
6、与 BigImageViewPager 的对比
两者名字相近、都做大图预览,但定位差异明显,适合互补而非互斥。
维度对比:
- 架构:BigImageViewer 模块化、引擎可插拔(Fresco / Glide);BigImageViewPager 一体化、绑定 Glide
- 渲染内核:前者以 SSIV 分块渲染为核心,主打极致低内存;后者用区块复用加载
- 媒体范围:前者专注图片(含 gif / webp);后者还内置视频预览(可选 Media3 插件)
- API:前者 showImage + ImageLoader.Callback;后者 ImagePreview 链式 + VideoPlayPolicy
- 协议:前者 MIT;后者 Apache 2.0
选择建议:
1. 已用 Fresco,或想要引擎中立 → BigImageViewer
2. 想要图片 + 视频一体预览、开箱即用 → BigImageViewPager
3. 对超大图内存极敏感 → BigImageViewer(SSIV 分块)
4. 需要的是单个大图查看控件,而非整套预览页 → BigImageViewer
7、使用建议与注意事项
使用建议:
- 初始化务必传 ApplicationContext,否则可能内存泄漏
- 本地文件用 Uri.parse("file://" + path),避免 Uri.fromFile 的编码问题
- RecyclerView / ViewPager 中复用视图时,需手动清理与重载图片
- 保存图片前自备存储权限,并在 IO 线程调用保存方法
注意事项:
- 通过 getSSIV() 拿底层控件后需判空(gif 不走 SSIV)
- 共享元素转场为实验性,可能出现闪烁
- Android 4.x 需强制 OkHttp 低于 3.13.0
- Picasso 适配器未实现、无 Coil 支持,选型前先确认
8、总结
BigImageViewer 以 SSIV 为渲染内核、把图片加载做成可插拔适配器(Fresco / Glide),用分块渲染把大图内存从约 80MB 压到 2–20MB。模块化设计让它能在 Fresco 与 Glide 项目里直接接入而不换技术栈,并提供缩略图、进度、动图、保存、预取等一整套能力。
对于已有 Fresco 或 Glide 技术栈、需要在大图场景压低内存的 App,引入核心库 + 对应适配器,在 Application 用 ApplicationContext 初始化,以 showImage 显示、ImageLoader.Callback 监听进度;若同时需要视频预览或开箱即用的整套预览页,则可考虑 BigImageViewPager,或让二者各司其职、搭配使用。
