首先是通过Gilde来下载图片,下面演示两种不同下载方式,并取得不同类型为Bitmap和File
下载Bitmap:
Glide.with(context).asBitmap().load(picUrl).into(object : SimpleTarget<Bitmap>() { override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) { //resource即为下载取得的bitmap } })
下载File:
Glide.with(context) .downloadOnly() .load(picUrl) .addListener(object : RequestListener<File> { override fun onLoadFailed( e: GlideException?, model: Any?, target: Target<File>?, isFirstResource: Boolean ): Boolean { return false } override fun onResourceReady( resource: File, model: Any?, target: Target<File>?, dataSource: DataSource?, isFirstResource: Boolean ): Boolean { //resource即为下载取得的图片File return false } }).preload()
获取到下载的Bitmap和File以后保存到本地并通知系统相册更新
首先是把Bitmap保存到本地:
Glide.with(context).asBitmap().load(picUrl).into(object : SimpleTarget<Bitmap>() { override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) { val destFile = createSaveFile( context, false, "${System.currentTimeMillis()}.jpg", "your_picture_save_path" ) saveBitmap2SelfDirectroy( context, resource, destFile ) } })
保存到本地目录分为SdCard目录和App的私有目录下
/** * 创建需要保存的文件 * @param isUseExternalFilesDir 是否使用getExternalFilesDir,false为保存在sdcard根目录下 * @param fileName 保存文件名 * @param folderName 保存在sdcard根目录下的文件夹名(isUseExternalFilesDir=false时需要) */ private fun createSaveFile( context: Context, isUseExternalFilesDir: Boolean, fileName: String, folderName: String? = "" ): File { val filePath = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.absolutePath!! } else { if (isUseExternalFilesDir) { context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.absolutePath!! } else { Environment.getExternalStorageDirectory().absolutePath } } return if (isUseExternalFilesDir) { File(filePath, fileName) } else { val file = File(filePath, folderName!!) if (!file.exists()) { file.mkdirs() } File(file, fileName) } } //保存Bitmap至本地 private fun saveBitmap2SelfDirectroy( context: Context, bitmap: Bitmap, file: File ) { try { val fos = FileOutputStream(file) bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos) fos.flush() fos.close() } catch (e: FileNotFoundException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } //通知系统图库更新 refreshSystemPic(context, file) }
最后是通知系统图库更新,首先主要在清单文件下注册app的FilePorvider
//在xml文件夹下创建file_path.xml <?xml version="1.0" encoding="utf-8"?> <resources> <paths> <external-path name="my_external_path" path="" /> <!-- Context.getExternalFilesDir(null) + "/path/" --> <external-files-path name="external_file_path" path="" /> <root-path name="root-path" path="" /> </paths> </resources> //在AndroidManifest中注册({applicationId}为应用包名) <provider android:name="androidx.core.content.FileProvider" android:authorities="{applicationId}.fileProvider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_path" /> </provider>
通知系统更新时,需要区分系统版本,分开处理Android10.0、Android7.0及之前的版本
/** * 通知系统相册更新 */ private fun refreshSystemPic(context: Context, destFile: File) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { insertPicInAndroidQ(context, destFile) } else { val value = ContentValues() value.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") value.put(MediaStore.Images.Media.DATA, destFile.absolutePath) context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, value) val contentUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { FileProvider.getUriForFile( context, "{applicationId}.fileProvider", destFile ) } else { Uri.fromFile(File(destFile.path)) } context.sendBroadcast( Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, contentUri ) ) } } /** * Android Q以后向系统相册插入图片 */ @RequiresApi(Build.VERSION_CODES.Q) private fun insertPicInAndroidQ(context: Context, insertFile: File) { val values = ContentValues() values.put(MediaStore.Images.Media.DESCRIPTION, insertFile.name) values.put(MediaStore.Images.Media.DISPLAY_NAME, insertFile.name) values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") values.put(MediaStore.Images.Media.TITLE, "Image.jpg") values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/") val external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI val resolver: ContentResolver = context.contentResolver val insertUri = resolver.insert(external, values) var inputStream: BufferedInputStream? var os: OutputStream? = null try { inputStream = BufferedInputStream(FileInputStream(insertFile)) if (insertUri != null) { os = resolver.openOutputStream(insertUri) } if (os != null) { val buffer = ByteArray(1024 * 4) var len: Int while (inputStream.read(buffer).also { len = it } != -1) { os.write(buffer, 0, len) } os.flush() } } catch (e: IOException) { e.printStackTrace() } finally { os?.close() } }
然后是File方式处理
Glide.with(context) .downloadOnly() .load(picUrl) .addListener(object : RequestListener<File> { override fun onLoadFailed( e: GlideException?, model: Any?, target: Target<File>?, isFirstResource: Boolean ): Boolean { return false } override fun onResourceReady( resource: File, model: Any?, target: Target<File>?, dataSource: DataSource?, isFirstResource: Boolean ): Boolean { //获取到下载得到的图片,进行本地保存 val destFile = createSaveFile( context, false, "${System.currentTimeMillis()}.jpg", "your_picture_save_path" ) copy(it, destFile) refreshSystemPic(context, destFile) return false } }).preload()
copy方式是把Glide下载的File移动到指定目录去
/** * 复制文件 * * @param source 输入文件 * @param target 输出文件 */ private fun copy(source: File?, target: File?) { var fileInputStream: FileInputStream? = null var fileOutputStream: FileOutputStream? = null try { fileInputStream = FileInputStream(source) fileOutputStream = FileOutputStream(target) val buffer = ByteArray(1024) while (fileInputStream.read(buffer) > 0) { fileOutputStream.write(buffer) } } catch (e: Exception) { e.printStackTrace() } finally { try { source?.delete() fileInputStream?.close() fileOutputStream?.close() } catch (e: IOException) { e.printStackTrace() } } }
总结
读写权限申请就不多说了,在使用的地方进行动态申请,AndroidQ要访问系统相册也需要WRITE_EXTERNAL_STORAGE权限
由于操作文件为耗时操作,demo中还用到了RxJava做线程调度
最后附上demo地址:https://github.com/chiu14578/GlideDownLoadPic
//更新时间:2020-10-20