关于使用Glide加载图片,并保存
这是我的Github地址:https://github.com/brokes6
我的博客:https://brokes6.github.io/
本篇已Kotlin为主要语言
思路
- 首先通过Glide来加载图片
- 在RecyclerView中使用
- 在外部,通过获取RecyclerView,在获取到ViewHodel,最后获取到Image
- 将获取到Image通过“holder.itemView.imageView.drawable.toBitmap()”保存为Bitmap
- 在通过requestContext.contextResolver的openOutputStream来存入本地图片文件夹
在RecyclerView中使用
-
如果使用了ViewPage,则先需要获取RecyclerView
val holder = (binding.viewPager[0] as RecyclerView)
通过调用viewpagep[0]来获取到RecyclerView
-
获取ViewHodel
val holder = (binding.viewPager[0] as RecyclerView).findViewHolderForAdapterPosition(binding.viewPager.currentItem) as PhotoViewPagerHolder
通过findViewHolderForAdapterPosition,传入Position 在转换为自己的ViewHodel即可
-
将Image转换为Bitmap
val bitmap = holder.itemView.imageView.drawable.toBitmap()
-
如果API是否大于29
- 大于29等于:由于大于等于29,所以就只能使用 requireContext().contentResolver.openOutputStream 来存储图片
- 小于29:可以直接使用 MediaStore.Images.Media.insertImage 来保存
-
由于不管是否大于29,都可以使用 requireContext().contentResolver.openOutputStream 来保存图片,所以就讲这个了
-
openOutputStream 接收2个参数(1.uri地址,2.mode模式(可无视))
-
创建一个空的 Image 保存 Uri
val imageUrl = requireContext().contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, ContentValues())?: kotlin.run { Toast.makeText(context, "存储失败", Toast.LENGTH_SHORT).show() }
因为获取完的 Uri 是可为空的,所以需要写一个为空则干什么
因为这个 Dome 是在 Fragment中,所以需要使用到 requestContext()
-
将图片保存到本地
requireContext().contentResolver.openOutputStream(imageUrl as Uri).use { if (bitmap.compress(Bitmap.CompressFormat.PNG,90,it)){ MainScope().launch { Toast.makeText(context, "存储成功", Toast.LENGTH_SHORT).show() } }else{ MainScope().launch { Toast.makeText(context, "存储失败", Toast.LENGTH_SHORT).show() } } }
通过调用 Bitmap.compress() 来进行保存,我们可以根据 compress 的返回值来判断是否保存成功
compress 接收3个参数:
- 保存格式
- 压缩程度(如果格式为JPEG,那么将无法压缩)
- 输出流
Kotlin语法糖:use{} 它配合流使用在使用完流之后,自动关闭
-
由于保存图片本身是在主线程,如果遇到图片较大,那么可能会阻塞主线程,所以我们需要将他在子线程中运行
private suspend fun saveImage() { withContext(Dispatchers.IO){ val holder = (binding.viewPager[0] as RecyclerView).findViewHolderForAdapterPosition(binding.viewPager.currentItem) as PhotoViewPagerHolder val imageUrl = requireContext().contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, ContentValues())?: kotlin.run { Toast.makeText(context, "存储失败", Toast.LENGTH_SHORT).show() } requireContext().contentResolver.openOutputStream(imageUrl as Uri).use { if (holder.itemView.imageView.drawable.toBitmap().compress(Bitmap.CompressFormat.PNG,90,it)){ MainScope().launch { Toast.makeText(context, "存储成功", Toast.LENGTH_SHORT).show() } }else{ MainScope().launch { Toast.makeText(context, "存储失败", Toast.LENGTH_SHORT).show() } } } } }
于是使用Kotlin中的协程,将方法名前加上suspend,方法内部使用 withContext(Dispatchers.IO){} 包裹起来,用来限定范围
-
最后则可以通过Lifecycle来调用
viewLifecycleOwner.lifecycleScope.launch { saveImage() }