如何使用Glide下载图像到设备内部存储

发布于 2025-02-08 19:04:59 字数 1692 浏览 2 评论 0原文

我有一个Recyclerview,它使用GLIDE显示Firebase实时数据库中的图像。在RecyClerview中,我还有一个下载按钮。当用户单击按钮时,希望将Firebase的图像下载到设备内部存储中。

适配器类

    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"
    }
}

数据列表类别

   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'

I have a recyclerview that uses Glide to display images from Firebase Realtime database. In the recyclerview I also have a download button. When a user clicks the button, want the image from Firebase to be downloaded into the device internal storage.

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'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

坐在坟头思考人生 2025-02-15 19:04:59
  1. 添加OKHTTP依赖关系

首先

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

,您需要将OKHTTP依赖性依赖于您的应用程序gradle: 注意:如果您正在进行改造,则不需要添加Okhttp依赖关系依赖性

  1. 创建下载功能

OK现在我们将添加下载逻辑在您的视图模型中,将OKHTTP实例声明和下载函数添加到您的视图模型:

注意:您可以将下载逻辑移至存储库或任何您想要的任何地方,这取决于您。

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. 下载函数从片段到适配器传递给

现在您需要将

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

您的适配器,您需要将下载函数传递给lambda函数中的适配器,片段中的适配器创建应该看起来像:您的适配器构造函数看起来像这样:

class AbstractAdapter(
    private val mContext: Context, 
    private val natureList: ArrayList<Nature>,
    private val downloadImage: (imageUrl: String) -> Unit
): RecyclerView.Adapter<AbstractAdapter.ViewHolder>()
  1. call downloctimage lambda lambda inslow downloctbtn inslow downloctbtn单击侦听器

现在,我们将在单击“侦听器”中添加下载图像

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" />

注意:此权限此权限仅限SQK版本&lt; = 28这就是为什么我们添加了android:maxSdkversion =“ 28”

我希望一切都清楚。
此代码应该给您想要的结果,请尝试一下,并告诉我是否有任何错误。

  1. Add Okhttp dependency

First of all you need to have okhttp dependency on your app gradle:

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

Note: if you are having retrofit no need to add okhttp dependency

  1. Create download function

Ok now we are going to add the download logic in your view model, add okhttp instance declaration and download function to your view model:

Note: you can move download logic to a repository or anywhere you want, it's up to you.

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. Pass download function from your fragment to your adapter

Now you need to pass your download function to your adapter inside a lambda function, adapter creation in your fragment should look like this:

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

Your adapter constructor will look like this:

class AbstractAdapter(
    private val mContext: Context, 
    private val natureList: ArrayList<Nature>,
    private val downloadImage: (imageUrl: String) -> Unit
): RecyclerView.Adapter<AbstractAdapter.ViewHolder>()
  1. Call downloadImage lambda inside downloadBtn click listener

now we will add downloadImage call inside the click listener

holder.downloadBtn.setOnClickListener {
    val imageUrl = natureList[position].space
    imageUrl?.let {
        downloadImage(it)
    }
}
  1. Add write external storage permission to AndroidManifest.xml

add this permission to your AndroidManifest.xml file to be able to add files to phone storage

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

Note: This permission is only required for sqk version <= 28 that's why we added android:maxSdkVersion="28"

I hope that everything is clear.
This code should give you the result that you want, try it and tell me if there is anything wrong.

他夏了夏天 2025-02-15 19:04:59

您也可以使用下载经理Bruv。只需创建一个OnItemClick界面,只需在主片段或类中实现此功能即可。

override fun onItemClick(item: String, pos:Int) {
    abstractData = item
    positionItem = pos

    if (checkSelfPermission(requireActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED ){
       requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQ_CODE)

    }else{

    startDownloading()
    }

    Toast.makeText(requireActivity(), "Saved to Internal storage/Pictures/AbstractWallpaper", Toast.LENGTH_LONG).show()

}

private fun startDownloading() {

    val request = DownloadManager.Request(Uri.parse(abstractData))
    request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
    request.setTitle("Abstract Wallpaper")
    request.setDescription("Your image is downloading")
    request.allowScanningByMediaScanner()
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES, "AbstractWallpapers")
    val manager = activity?.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    manager.enqueue(request)

    Toast.makeText(requireActivity(), "Download is starting...", Toast.LENGTH_LONG).show()
}

You can also use Download Manager bruv. Just create an OnItemClick interface and simply implement this function in your main fragment or class.

override fun onItemClick(item: String, pos:Int) {
    abstractData = item
    positionItem = pos

    if (checkSelfPermission(requireActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED ){
       requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQ_CODE)

    }else{

    startDownloading()
    }

    Toast.makeText(requireActivity(), "Saved to Internal storage/Pictures/AbstractWallpaper", Toast.LENGTH_LONG).show()

}

private fun startDownloading() {

    val request = DownloadManager.Request(Uri.parse(abstractData))
    request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
    request.setTitle("Abstract Wallpaper")
    request.setDescription("Your image is downloading")
    request.allowScanningByMediaScanner()
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_PICTURES, "AbstractWallpapers")
    val manager = activity?.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    manager.enqueue(request)

    Toast.makeText(requireActivity(), "Download is starting...", Toast.LENGTH_LONG).show()
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文