Jetpack Compose How to download image from URL and set to imageview?

Last updated Sep 02, 2021


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

 

 

Download Source code

 

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

Jetpack Compose How to download image from URL and set to imageview

 

 

Compose Image Donload Android

 

 

Android Image download

 

Conclusion: In this jetpack example we covered how to download image from url using WorkManager library.

 


Article Contributed By :
https://www.rrtutors.com/site_assets/profile/assets/img/avataaars.svg

25 Views

Subscribe For Daily Updates

Flutter Questions
Android Questions