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" |
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.
?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.
-->
Article Contributed By :
|
|
|
|
2571 Views |