Kotlin中如何将Glide加载的图片下载保存到设备内部存储
RecyclerView列表项Glide图片下载保存实现方案
前置说明
- 以下逻辑直接填充到
holder.downloadBtn.setOnClickListener即可,不需要改动现有Glide加载图片的代码 - 提供两种存储位置可选:应用内部私有存储(无权限要求)、系统公共图片目录(相册可见,高版本无权限要求)
- 自动复用Glide已有缓存,不会重复发起网络请求下载已加载过的图片
具体实现代码
holder.downloadBtn.setOnClickListener { val currentImgUrl = abstractList[position].abstract.toString() // 临时禁用按钮防止重复点击 it.isEnabled = false // 绑定item生命周期,列表滑动回收item时自动取消任务,避免内存泄漏 holder.itemViewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { val saveResult = runCatching { // 通过Glide拉取原始图片Bitmap val targetBitmap = Glide.with(mContext) .asBitmap() .load(currentImgUrl) .submit() .get() // -------------------------- 存储位置二选一即可 -------------------------- // 选项1:存储到应用内部私有目录(无需任何权限,仅本应用可访问,卸载应用自动删除) val saveDir = mContext.getDir("abstract_images", Context.MODE_PRIVATE) val saveFileName = "abstract_${System.currentTimeMillis()}.jpg" val targetFile = File(saveDir, saveFileName) FileOutputStream(targetFile).use { outputStream -> targetBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) outputStream.flush() } targetFile.absolutePath /* // 选项2:存储到系统公共Pictures目录(相册可查看,所有应用可访问,卸载不删除) // Android 10及以上无需存储权限,Android 9及以下需要动态申请WRITE_EXTERNAL_STORAGE权限 val contentValues = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, "abstract_${System.currentTimeMillis()}.jpg") put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { put(MediaStore.Images.Media.RELATIVE_PATH, "${Environment.DIRECTORY_PICTURES}/AbstractGallery") put(MediaStore.Images.Media.IS_PENDING, 1) } } val contentResolver = mContext.contentResolver val insertUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)!! contentResolver.openOutputStream(insertUri).use { outputStream -> targetBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream!!) outputStream.flush() } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { contentValues.clear() contentValues.put(MediaStore.Images.Media.IS_PENDING, 0) contentResolver.update(insertUri, contentValues, null, null) } insertUri.toString() */ } // 切回主线程更新UI withContext(Dispatchers.Main) { holder.downloadBtn.isEnabled = true saveResult.onSuccess { savePath -> Toast.makeText(mContext, "图片保存成功:$savePath", Toast.LENGTH_SHORT).show() }.onFailure { error -> Toast.makeText(mContext, "保存失败:${error.message}", Toast.LENGTH_SHORT).show() } } } }
必要配置
- 项目需要引入lifecycle ktx依赖才能使用
lifecycleScope,在模块级build.gradle添加依赖:
dependencies { implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2" }
- 如果选择公共目录存储且需要适配Android 9(API 28)及以下版本,需要在AndroidManifest.xml添加权限声明,并在下载前动态申请权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
注意点
- 不要在主线程调用Glide的
submit().get(),会阻塞UI导致卡顿 - 文件名建议使用唯一标识(时间戳、图片唯一ID),避免同名文件被覆盖
- Glide的缓存机制会自动命中已经加载过的图片,不会重复消耗流量下载
内容的提问来源于stack exchange,提问作者Khumo Mashapa
相关产品推荐
相关产品推荐

