我有一个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) {

}

Update

First error

e: C:\Users\Khumo Kwezi Mashapa\AndroidStudioProjects\MyNotepad\app\src\main\java\com\khumomashapa\notes\fragments\NatureWallpapers.kt: (65, 17): Unresolved reference: viewModel

Second error

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. 添加Okhttp依赖项

首先,您需要对应用程序gradle具有okhttp依赖性:

implementation("com.squareup.okhttp3:okhttp:4.10.0")

Note:如果您正在进行改装,则无需添加okhttp依赖项

  1. 创建下载功能

好的,现在我们要在视图模型中添加下载逻辑,在视图模型中添加okhttp实例声明和下载功能:

Note:您可以将下载逻辑移动到存储库或任何您想要的地方,这取决于您.

class YourViewModel : ViewModel() {

    // add okhttp instance to your view model or you inject it with hilt if your using dependency injection
    private val okHttpClient = OkHttpClient.Builder().build()

    // add this function to your view model
    fun downloadImage(imageUrl: String) {
        val request = Request.Builder()
            .url(imageUrl)
            .build()

        okHttpClient.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                // Download Failed, you can show error to the user
            }

            override fun onResponse(call: Call, response: Response) {
                if (!response.isSuccessful) {
                    // Download Failed, you can show error to the user
                    return
                }

                response.body?.let { responseBody ->
                    try {
                        // Convert response body to byte array
                        val imageByteArray = responseBody.byteStream().readBytes()

                        // Split image url so we can get the image name
                        val words = imageUrl.split("/").toTypedArray()

                        // Get the image name
                        val imageName = words.last()

                        // Init pathName (Downloads Directory)
                        val pathName = "${Environment.getExternalStorageDirectory()}/${Environment.DIRECTORY_DOWNLOADS}"

                        // Create New file for the image
                        val file = File(pathName, imageName)

                        // Set byteArray To Image File
                        file.writeBytes(imageByteArray)
                    } catch(e: IOException) {
                        // Saving Image Failed, you can show error to the user
                        e.printStackTrace()
                    }
                }
            }
        })
    }

}
  1. 将下载功能从片段传递到适配器

现在,您需要将下载函数传递给lambda函数中的适配器,片段中的适配器创建应如下所示:

val adapter = AbstractAdapter(
    context = requireContext(),
    natureList = natureList, // your list here
    downloadImage = { imageUrl ->
        viewModel.downloadImage(imageUrl)
    }
)

适配器构造函数如下所示:

class AbstractAdapter(
    private val mContext: Context, 
    private val natureList: ArrayList<Nature>,
    private val downloadImage: (imageUrl: String) -> Unit
): RecyclerView.Adapter<AbstractAdapter.ViewHolder>()
  1. 在downloadBtn中调用downloadImage lambda单击侦听器

现在,我们将在click侦听器中添加downloadImage调用

holder.downloadBtn.setOnClickListener {
    val imageUrl = natureList[position].space
    imageUrl?.let {
        downloadImage(it)
    }
}
  1. 将写外部存储权限添加到AndroidManifest.xml

将此权限添加到您的AndroidManifest.xml文件,可将文件添加到手机存储中

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="28" />

Note:此权限仅适用于sqk版本<;=28所以我们加了android:maxSdkVersion="28"

我希望一切都很清楚.

Android相关问答推荐

AdMob:MobileAds. initialize()—java. lang. xml对于某些设备不能强制转换为java. lang. String""

如何在安卓系统上使用Float16霓虹灯?

如何在Jetpack Compose中使用Box Composable来实现这种布局?

Kotlin DSL:为什么我可以从Play Store获取发布版本的日志(log)?

无法在Android中创建通知频道

这款应用与最新版本的Android不兼容.在Android 14中

格雷德的两个星号是什么意思?非路径

对支持哪些数据存储区方法感到困惑

为什么它显示我的空白屏幕?

在更改MuableState的值后,Android API 26(Oreo)上的Composable不能重新组合

如何迭代 SqlDelight Select 结果而不将所有内容加载到内存中?

当 EditText 用于在 android studio 中将字符串发送到 firebase 时,仅允许安全调用错误

当 Jetpack Compose 中的第一个文本很长时,将省略号添加到第一个文本

ImageBitmap 使用 Glide/Coil 到画布

ionic - capacitor - Android 风味 - 无法在模拟器或真实设备中运行应用程序

如何在 Dolphin 中启用 android studio new logcat | 2021.3.1 金丝雀 6?

使用 Jetpack Compose 时,如何以简单的方式在 Color.kt 中定义 colored颜色 ?

Android Compose webview 被拉伸

Android YouTube SDK - 视频无法在某些 Android 设备中播放

如何满足设备内框架的无效 Wear OS 屏幕截图Wear OS 表盘策略违规?