Jetpack Compose How to download image from URL and set to imageview?
Learn how to download images from the internet using Jetpack Compose. Follow this step-by-step tutorial to implement image loading in Android on rrtutors.com.
In this Jetpack compose tutorial we will learn How to download Image from Url in Android application using Jetpack Compose.
To download image from url we are going to use Work Manager.
Work Manager is Jetpack component library introduced in android, With this developers can easily schedule asynchronous tasks which they can expected to run even if the application exits or while device restarts.
To use work manager we need to import dependencies in build.gradle file
def work_version = "2.5.0" implementation "androidx.work:work-runtime-ktx:$work_version" |
Define the work
To do any task we make as work, this work is defined using the Coroutine Worker class which contains a suspending version of doWork().
This method will runs asynchronously in a background thread that will be created by Work Manager.
Note: CoroutineWorker.doWork() is a suspending function.
Lets define DownloadFileWorker.kt
package com.example.jetpack.workers
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import kotlinx.coroutines.Dispatchers
import java.net.URL
import java.util.*
import kotlinx.coroutines.withContext
class DownloadFileWorker(context: Context, params: WorkerParameters) :
CoroutineWorker(context, params) {
override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
val imageUrl = inputData.getString("url")
val destination = inputData.getString("destination")
try {
if (destination == null || imageUrl == null) {
return@withContext Result.failure()
}
val outputStream =
applicationContext.contentResolver?.openOutputStream(Uri.parse(destination))
var bitmap: Bitmap? = null
try {
val inputStream = URL(imageUrl).openStream() // Download Image from URL
bitmap = BitmapFactory.decodeStream(inputStream) // Decode Bitmap
inputStream.close()
} catch (e: Exception) {
e.printStackTrace()
}
try {
bitmap?.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
// Flush the stream
outputStream?.flush()
outputStream?.close()
return@withContext Result.success()
} catch (ex: Exception) {
return@withContext Result.failure()
}
}
}
|
The doWork() method return the work status, this status might be any of three status
Result.success(): which will tells work finished successfully.Result.failure(): which will tells work failed.Result.retry(): which will tells work failed and should be tried at another time according to its retry policy.
Add network_security_config.xml file inside res/xml folder
?xml version="1.0" encoding="utf-8"?>
|
Add network_security_config.xml file in Android Manifest in application tag
android:networkSecurityConfig="@xml/network_security_config" |
Add Internet Permission in Android Manifest
uses-permission android:name="android.permission.INTERNET"/>
|
Add Download button in compose function and on clicking button we are going to ask user to select the destination where he/she wants to download the image
val mimeType = fetchMimeTypeFromUrl() val fileName = "flower_image.jpg"
Column(
content = {
Text(fileName)
TextButton(onClick = {
if (fileName.isNotEmpty() && mimeType?.isNotEmpty() == true) {
val intent = Intent()
intent.action = Intent.ACTION_CREATE_DOCUMENT
val mimeTypes: Array = arrayOf(mimeType)
intent.type = mimeType
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
intent.putExtra(Intent.EXTRA_TITLE, fileName)
launcher.launch(
Intent.createChooser(
intent,
"Select a target to download the file"
)
)
}
}, content = {
Text(text = "Download")
})
}, modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
.padding(16.dp)
)
|
Once user select the destination we are going to create work request using OneTimeWorkRequest
val selectedFile = remember { mutableStateOf(null) }
val showImage = remember { mutableStateOf(null) }
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
selectedFile.value = it
}
val mimeType = fetchMimeTypeFromUrl()
val fileName = "flower_image.jpg"
if (selectedFile.value != null && selectedFile.value?.resultCode == Activity.RESULT_OK) {
val uri = selectedFile.value?.data?.data
if (uri != null) {
val builder = Data.Builder()
builder.putString("destination", uri.toString())
builder.putString("url", url)
val inputParams = builder.build()
val downloadFileWorker = OneTimeWorkRequest.Builder(DownloadFileWorker::class.java)
.setInputData(inputParams)
.build()
val workManager = WorkManager.getInstance(context)
workManager.enqueue(downloadFileWorker)
val outputWorkInfo: LiveData =
workManager.getWorkInfoByIdLiveData(downloadFileWorker.id)
outputWorkInfo.observe(context as MainActivity, Observer {
if (it.state == WorkInfo.State.SUCCEEDED) {
showImage.value=uri
} else if (it.state == WorkInfo.State.FAILED) {
}
})
}
}
|
Once download is complete lets show the image in image view
if (showImage.value != null) {
val bitmap = remember { mutableStateOf(null) }
Glide.with(context)
.asBitmap()
.load(showImage.value)
.into(object : CustomTarget() {
override fun onLoadCleared(placeholder: Drawable?) {}
override fun onResourceReady(
resource: Bitmap,
transition: Transition?
) {
bitmap.value = resource
}
})
val value = bitmap.value
if (value != null){
Image(value.asImageBitmap(), contentDescription = "image", Modifier.fillMaxWidth())
}else{
Text("Downloading Image...")
}
}
|
Full Code
package com.example.jetpack.widget
import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.webkit.MimeTypeMap
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.work.Data
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkInfo
import androidx.work.WorkManager
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.example.jetpack.MainActivity
import com.example.jetpack.workers.DownloadFileWorker
const val url =
"http://digitalcommunications.wp.st-andrews.ac.uk/files/2019/04/JPEG_compression_Example.jpg"
@Composable
fun DownloadImageFromUrl() {
val context = LocalContext.current
val selectedFile = remember { mutableStateOf(null) }
val showImage = remember { mutableStateOf(null) }
val launcher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
selectedFile.value = it
}
if (selectedFile.value != null && selectedFile.value?.resultCode == Activity.RESULT_OK) {
val uri = selectedFile.value?.data?.data
if (uri != null) {
val builder = Data.Builder()
builder.putString("destination", uri.toString())
builder.putString("url", url)
val inputParams = builder.build()
val downloadFileWorker = OneTimeWorkRequest.Builder(DownloadFileWorker::class.java)
.setInputData(inputParams)
.build()
val workManager = WorkManager.getInstance(context)
workManager.enqueue(downloadFileWorker)
val outputWorkInfo: LiveData =
workManager.getWorkInfoByIdLiveData(downloadFileWorker.id)
outputWorkInfo.observe(context as MainActivity, Observer {
if (it.state == WorkInfo.State.SUCCEEDED) {
showImage.value=uri
} else if (it.state == WorkInfo.State.FAILED) {
}
})
}
}
val mimeType = fetchMimeTypeFromUrl()
val fileName = "flower_image.jpg"
Column(
content = {
Text(fileName)
TextButton(onClick = {
if (fileName.isNotEmpty() && mimeType?.isNotEmpty() == true) {
val intent = Intent()
intent.action = Intent.ACTION_CREATE_DOCUMENT
val mimeTypes: Array = arrayOf(mimeType)
intent.type = mimeType
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
intent.putExtra(Intent.EXTRA_TITLE, fileName)
launcher.launch(
Intent.createChooser(
intent,
"Select a target to download the file"
)
)
}
}, content = {
Text(text = "Download")
})
if (showImage.value != null) {
val bitmap = remember { mutableStateOf(null) }
Glide.with(context)
.asBitmap()
.load(showImage.value)
.into(object : CustomTarget() {
override fun onLoadCleared(placeholder: Drawable?) {}
override fun onResourceReady(
resource: Bitmap,
transition: Transition?
) {
bitmap.value = resource
}
})
val value = bitmap.value
if (value != null){
Image(value.asImageBitmap(), contentDescription = "image", Modifier.fillMaxWidth())
}else{
Text("Downlaoding Image...")
}
}
}, modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
.padding(16.dp)
)
}
private fun fetchMimeTypeFromUrl(): String? {
var type: String? = null
try {
val extension = MimeTypeMap.getFileExtensionFromUrl(url)
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
}
} catch (e: Exception) {
}
return type
}
|
Image
![]() |
![]() |
![]() |
Conclusion: In this jetpack example we covered how to download image from url using WorkManager library.


