Glide下载图片并保存到本地

首先是通过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

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值