Gallery应用从JSON API获取URL后异步加载图片实现方案咨询
Android Flickr图库实现方案
不要试图单靠某一个库或者自己裸写网络/解码逻辑覆盖全流程,按职责拆分用成熟组件组合实现即可,稳定性和开发效率最高。
推荐依赖栈
按职责拆分选对应成熟库,避免重复造轮子踩兼容坑:
- 接口请求层:Retrofit(底层封装OkHttp,自动处理连接复用、重定向、流读取)
- JSON解析层:Gson/Moshi,自动映射返回数据到实体类,无需手动解析字段
- 图片加载层:Glide,全权负责图片异步下载、解码、缓存、生命周期绑定,适配RecyclerView复用逻辑
- 异步调度:Kotlin协程(Java项目可替换为RxJava),自动完成线程切换,替代废弃的AsyncTask和裸写Thread的不稳定实现
具体实现步骤
1. 拉取feed数据提取图片链接
首先匹配Flickr接口返回结构定义实体类,接口返回的media字段下的m属性即为可直接访问的图片直链:
// 单条图片数据实体 data class FlickrPhoto( val title: String, val media: Media ) data class Media( val m: String // 图片直链 ) // 接口最外层返回结构 data class FlickrFeedResp( val items: List<FlickrPhoto> )
定义Retrofit请求接口,用suspend关键字修饰请求方法,配合协程保证请求默认在IO线程执行,不阻塞UI:
interface FlickrService { @GET("services/feeds/photos_public.gne?format=json&nojsoncallback=1&tags=cat") suspend fun getCatPhotoFeed(): FlickrFeedResp }
初始化Retrofit时设置baseUrl为https://www.flickr.com/,绑定对应JSON解析转换器即可。请求成功后直接遍历返回的items列表,取每个元素的media.m就能拿到所有图片链接,全程无需手动处理流读取、JSON字段解析。
2. 图片异步加载展示
这部分逻辑完全交给Glide实现,不要自己用OkHttp读流再调用BitmapFactory解码——你之前遇到的流为空、加载失败问题,本质是裸写逻辑没覆盖这些兼容点:
- OkHttp响应体的字节流是一次性读取的,手动传递给BitmapFactory时很容易因为流提前关闭、读取不全导致解码失败
- Flickr部分图片存在3xx重定向,裸写OkHttp如果没配置跟随重定向、请求头透传会拿到空响应
- BitmapFactory默认对渐进式JPEG、动态WebP等格式的兼容需要手动配置,很容易出现解码返回null
- RecyclerView复用时如果不手动取消滑出屏幕的请求,会出现请求错乱、资源泄漏
在RecyclerView Adapter的onBindViewHolder方法中直接调用Glide加载即可:
Glide.with(holder.itemView.context) .load(photoUrl) // 前面提取到的media.m链接 .placeholder(R.drawable.placeholder) // 加载中占位图 .error(R.drawable.load_error) // 加载失败占位图 .override(Target.SIZE_ORIGINAL) // 按需设置图片采样尺寸,减少内存占用 .into(holder.photoIv)
Glide会自动完成后台线程下载、图片解码采样、内存/磁盘两级缓存,滑动时自动取消不可见item的加载请求,全程不会阻塞UI线程,只要链接有效加载成功率接近100%。
注意事项
- 不要自己new Thread处理网络请求,没有统一的线程调度、生命周期绑定很容易出现内存泄漏、回调丢到子线程无法更新UI的问题
- 不要手动实现图片下载解码逻辑,Glide已经覆盖了几乎所有Android版本的图片兼容坑,自己重复实现投入产出比极低
- Retrofit初始化时记得配置OkHttp的超时时间,避免弱网下请求卡死
内容的提问来源于stack exchange,提问作者Bad Player
相关产品推荐
相关产品推荐

