You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Glide将Firebase图片下载至设备内部存储并解决报错

功能需求

现有基于Android的RecyclerView组件,通过Glide加载Firebase实时数据库存储的图片。RecyclerView每个列表项内置下载按钮,需要实现点击按钮时,将对应位置的Firebase图片下载并保存到设备本地存储的功能。

现有代码

适配器类(Adapter class)

class NatureAdapter(private val mContext: Context, private val natureList: ArrayList<Nature>) : RecyclerView.Adapter<NatureAdapter.ViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.nature_image_view, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        Glide.with(mContext)
            .load(natureList[position].space)
            .into(holder.imageView)
    }

    override fun getItemCount(): Int {
        return natureList.size
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var imageView: ImageView = itemView.findViewById(R.id.NatureView)
    }

    companion object {
        private const val Tag = "RecyclerView"
    }
}

数据实体类(Data list class)

class Nature (var space: String? = null) {

}
现存编译报错
  • 第一个报错
e: C:\Users\Khumo Kwezi Mashapa\AndroidStudioProjects\MyNotepad\app\src\main\java\com\khumomashapa\notes\fragments\NatureWallpapers.kt: (65, 17): Unresolved reference: viewModel
  • 第二个报错
e: C:\Users\Khumo Kwezi Mashapa\AndroidStudioProjects\MyNotepad\app\src\main\java\com\khumomashapa\notes\fragments\NatureWallpapers.kt: (120, 93): No value passed for parameter 'downloadImage'
实现方案与报错解决

报错根因

  1. Unresolved reference: viewModel:NatureWallpapers Fragment中未初始化viewModel变量就直接调用,编译器找不到对应引用。
  2. No value passed for parameter 'downloadImage':调用函数/类构造方法时,没有给名为downloadImage的必传参数传入对应值。

完整功能实现

1. 补全适配器逻辑

首先在列表项布局中确认下载按钮存在,id设为downloadBtn,修改适配器代码补充点击下载逻辑,同时适配不同Android版本的存储权限规则:

class NatureAdapter(
    private val mContext: Context,
    private val natureList: ArrayList<Nature>
) : RecyclerView.Adapter<NatureAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.nature_image_view, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val currentImageUrl = natureList[position].space
        Glide.with(mContext)
            .load(currentImageUrl)
            .into(holder.imageView)

        holder.downloadBtn.setOnClickListener {
            currentImageUrl?.let { url ->
                if (checkStoragePermission(mContext)) {
                    saveImageToLocal(mContext, url)
                } else {
                    (mContext as? AppCompatActivity)?.let {
                        ActivityCompat.requestPermissions(
                            it,
                            getRequiredPermissions(),
                            REQUEST_STORAGE_CODE
                        )
                    }
                }
            }
        }
    }

    override fun getItemCount() = natureList.size

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val imageView: ImageView = itemView.findViewById(R.id.NatureView)
        val downloadBtn: Button = itemView.findViewById(R.id.downloadBtn)
    }

    companion object {
        private const val Tag = "RecyclerView"
        private const val REQUEST_STORAGE_CODE = 1001
    }
}

2. 添加工具方法

在适配器同级或公共工具类中添加权限检查、图片下载相关方法:

// 获取当前系统版本需要的存储权限
private fun getRequiredPermissions(): Array<String> {
    return when {
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> arrayOf(Manifest.permission.READ_MEDIA_IMAGES)
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> emptyArray() // Android10+使用分区存储,无需写存储权限
        else -> arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
    }
}

// 存储权限检查
private fun checkStoragePermission(context: Context): Boolean {
    return getRequiredPermissions().all {
        ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
    }
}

// 下载图片到本地并通知系统相册更新
private fun saveImageToLocal(context: Context, imageUrl: String) {
    CoroutineScope(Dispatchers.IO).launch {
        runCatching {
            val saveDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
            val targetFile = File(saveDir, "Nature_${System.currentTimeMillis()}.jpg")
            // 用Glide下载原图
            Glide.with(context)
                .asFile()
                .load(imageUrl)
                .submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
                .get()
                .copyTo(targetFile, overwrite = true)
            // 扫描文件让相册识别
            MediaScannerConnection.scanFile(
                context,
                arrayOf(targetFile.absolutePath),
                arrayOf("image/jpeg"),
                null
            )
            withContext(Dispatchers.Main) {
                Toast.makeText(context, "图片下载完成", Toast.LENGTH_SHORT).show()
            }
        }.onFailure { e ->
            withContext(Dispatchers.Main) {
                Toast.makeText(context, "下载失败: ${e.message}", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

3. 修复编译报错

  1. 修复Unresolved reference: viewModel
    • 如果需要使用ViewModel,在NatureWallpapers Fragment中先初始化对应ViewModel实例:
      // 在Fragment类内部声明
      private val viewModel: NatureWallpapersViewModel by viewModels()
      
    • 如果不需要使用ViewModel,直接删除Fragment第65行调用viewModel的代码即可。
  2. 修复No value passed for parameter 'downloadImage'
    定位到Fragment第120行代码,找到调用时缺少downloadImage参数的位置:
    • 如果该参数是多余的,直接在对应函数/构造方法定义中删除该必传参数,或给参数设置默认值= {}
    • 如果该参数是需要的,传入对应实现即可,示例:
      // 错误写法(漏传参数)
      val adapter = NatureAdapter(requireContext(), natureList)
      // 正确写法(传入downloadImage参数实现)
      val adapter = NatureAdapter(
          mContext = requireContext(),
          natureList = natureList,
          downloadImage = { url -> saveImageToLocal(requireContext(), url) }
      )
      

注意:需要在AndroidManifest.xml中补充对应存储权限声明,否则下载功能无法正常使用。

内容的提问来源于stack exchange,提问作者Kwezi Mashapa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 09:24:13