Kotlin:如何将互联网上的图像保存到内部存储器中

6

我刚开始接触Android Studio和Kotlin,需要从互联网加载图片并将其保存到手机上。我尝试使用Glide将图片加载为位图,然后保存,但没有成功。这段代码是我找到的最好的东西,但它不起作用。

try {
var bitmap = Glide.with(this)
        .asBitmap()
        .load("https://s3.amazonaws.com/appsdeveloperblog/Micky.jpg")
        .apply(RequestOptions().override(100).downsample(DownsampleStrategy.CENTER_INSIDE).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE))
        .submit().get()
    val wrapper = ContextWrapper(applicationContext)
    var file = wrapper.getDir("Images", Context.MODE_PRIVATE)
    file = File(file, "img.jpg")
    val out = FileOutputStream(file)
    bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out)
    out.flush()
    out.close()
}
catch (e: Exception) {
    println(e)
}

我理解的问题在于Glide中的 ".submit().get()" 部分。但是如果我将它移除,则压缩功能将无法正常工作。
2个回答

6

submit(): 返回一个可以用于在后台线程上进行阻塞获取的 future 对象。

get(): 如果需要,等待计算完成,然后检索其结果。

如果您要从 URL 下载图像并将其保存到内部存储中,则应使用后台线程来执行此操作。如果在主线程上调用,则可能会导致应用程序抛出 ANR 对话框。

这里我将演示如何使用 AsyncTask API 下载和保存图像。

首先编写一个类来下载和保存图像。

class DownloadAndSaveImageTask(context: Context) : AsyncTask<String, Unit, Unit>() {
    private var mContext: WeakReference<Context> = WeakReference(context)

    override fun doInBackground(vararg params: String?) {
        val url = params[0]
        val requestOptions = RequestOptions().override(100)
            .downsample(DownsampleStrategy.CENTER_INSIDE)
            .skipMemoryCache(true)
            .diskCacheStrategy(DiskCacheStrategy.NONE)

        mContext.get()?.let {
            val bitmap = Glide.with(it)
                .asBitmap()
                .load(url)
                .apply(requestOptions)
                .submit()
                .get()

            try {
                var file = it.getDir("Images", Context.MODE_PRIVATE)
                file = File(file, "img.jpg")
                val out = FileOutputStream(file)
                bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out)
                out.flush()
                out.close()
                Log.i("Seiggailion", "Image saved.")
            } catch (e: Exception) {
                Log.i("Seiggailion", "Failed to save image.")
            }
        }
    }
}

然后在活动中只需调用。
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        DownloadAndSaveImageTask(this).execute("https://s3.amazonaws.com/appsdeveloperblog/Micky.jpg")
    }
}

如果您想保存到内部存储

var file = File(it.filesDir, "Images")
if (!file.exists()) {
    file.mkdir()
}
file = File(file, "img.jpg")

它会将图像保存在路径data/data/yourapppackagename/files/Images/img.jpg中。


我尝试了你的代码,它显示图像已保存,但我无法在任何地方找到它。你能帮我理解现在出了什么问题吗? - Seiggailion
我使用指令获取绝对路径,它是“/data/user/0/fi.jamk.k8760.stack_harkka/app_Recent/img.jpg”。我以为当我使用这个指令 var file = it.getDir("Images", Context.MODE_PRIVATE) 时,文件将保存到“Images”文件夹中。所以这意味着我理解错了,我仍然需要定义目录吗? - Seiggailion
在保存图像之前,您必须声明并启用外部存储权限以进行写入。 - Son Truong
1
我的应用程序没有访问存储的权限。现在它可以工作了。谢谢你,你救了我的命! - Seiggailion
如何使用此类而不压缩图像来保存图像? - Zef
显示剩余4条评论

1

只需使用此方法

    fun DownloadImageFromPath(path: String?) {
    var `in`: InputStream? = null
    var bmp: Bitmap? = null
    val iv = findViewById<View>(R.id.imagFullImage) as ImageView
    var responseCode = -1
    try {
        val url = URL(path) //"http://192.xx.xx.xx/mypath/img1.jpg
        val con: HttpURLConnection = url.openConnection() as HttpURLConnection
        con.setDoInput(true)
        con.connect()
        responseCode = con.getResponseCode()
        if (responseCode == HttpURLConnection.HTTP_OK) {
            //download
            `in` = con.getInputStream()
            bmp = BitmapFactory.decodeStream(`in`)
            `in`.close()
            iv.setImageBitmap(bmp)
        }
    } catch (ex: Exception) {
        Log.e("Exception", ex.toString())
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接