URL 이미지 혹은 파일을 특정 디렉토리에 다운로드하는 간단한 클래스를 만들었다. 간단하지만 예외 케이스에 최대한 대응하도록 견고하게 구현했다.
OkHttp3
implementation("com.squareup.okhttp3:okhttp:4.9.0")
AndroidManifest
<uses-permission android:name="android.permission.INTERNET" />
UrlDownloader
import androidx.annotation.WorkerThread
import java.io.File
import java.io.IOException
import okhttp3.OkHttpClient
import okhttp3.Request
import okio.sink
class UrlDownloader(
private val url: String,
private val headers: Map<String, String>?,
private val file: File,
) {
@WorkerThread
@Throws(Exception::class)
fun download(): File {
val destDirectory: File = checkNotNull(file.parentFile)
if (!destDirectory.exists()) {
destDirectory.mkdirs()
}
val tempFile = File.createTempFile("temp_", null, destDirectory)
try {
downloadToTempFile(tempFile)
if (!tempFile.renameTo(file)) {
throw IOException("Failed rename to target file")
}
return file
} catch (ex: Exception) {
tempFile.delete()
throw ex
}
}
private fun downloadToTempFile(tempFile: File) {
val request = Request.Builder()
.url(url)
.addHeaders()
.build()
okHttpClient.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw IOException("invalid response code: ${response.code}")
}
tempFile.sink().use {
checkNotNull(response.body).source().readAll(it)
}
}
}
private fun Request.Builder.addHeaders() = apply {
headers?.entries?.forEach {
addHeader(it.key, it.value)
}
}
companion object {
private val okHttpClient = OkHttpClient()
}
}
Test code
private fun test() {
val url =
"https://1.bp.blogspot.com/-73nbn4r0Imk/YKMtQF8ZPlI/AAAAAAAAQjs/TzvtHpXiFNcQJUM-ltLvyFRv7ezLwpWugCLcBGAsYHQ/s0/Untitled.jpeg"
val file = File(externalCacheDir, "dir4/2.jpg")
Thread {
UrlDownloader(url, headers = null, file).download()
}.start()
}