The old way of downloading an image or a file with URL is first to get the URL, create an InputStream instance, open the URL by using the HttpURLConnection class, then decode the bitmap or file and compress them and put the input stream instance to the decoded bitmap or file. This way, we need to put all the code into the doInBackground() method of AsyncTask class (will get exception otherwise), which is quite inconvenient. Therefore, there is the DownloadManager class.
DownloadManager for Android Developers
Here’s source code to implement the image downloading feature…
The download method
private fun downloadImage() {
//TODO("not implemented")
val destinationPath = "/wikiedu/images"
val url = Uri.parse(courseUpload?.thumbUrl)
val mDir = File(Environment.getExternalStorageDirectory(), "/wikiedu/images/")
val downloadMgr: DownloadManager = context?.
getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
try {
if (!mDir.exists()) {
mDir.mkdir()
Timber.d("Folder created at " + mDir)
}
val downloadRequest: DownloadManager.Request = DownloadManager.Request(url)
/**Downloaded image will be stored in Downloads directory of a device if no destination dir is set **/
downloadRequest.setAllowedNetworkTypes(DownloadManager
.Request.NETWORK_WIFI or DownloadManager.Request.
NETWORK_MOBILE).setAllowedOverMetered(true)
.setNotificationVisibility(DownloadManager.Request.
VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setAllowedOverMetered(true).setAllowedOverRoaming(false)
.setTitle("Wikiedu Image Download")
.setDescription("Downloading Image")
.setDestinationInExternalPublicDir
(destinationPath, mDir.absolutePath)
downloadID = downloadMgr.enqueue(downloadRequest)
onDownloadCompleteReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
if (downloadID == id) {
Toast.makeText(context, "Download complete!\n Image "
+ courseUpload?.fileName + " saved to "+ mDir,
Toast.LENGTH_LONG).show()
Timber.d("image saved to " + mDir)
}
}
}
//Register download broadcast receiver
context?.registerReceiver(onDownloadCompleteReceiver,
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}catch (ie: IOException) {
ie.stackTrace
}
}
...
//Unregistered the download broadcast receiver in onDestroy() to clear download notifiaction after each download
override fun onDestroy() {
super.onDestroy()
context?.unregisterReceiver(onDownloadCompleteReceiver)
}
Set Request Permission:
private fun downloadImageWithPermission() {
val permissionType = android.Manifest.permission.WRITE_EXTERNAL_STORAGE
val isGranted = context?.applicationContext?.let {
ContextCompat.checkSelfPermission(it,android.Manifest
.permission.WRITE_EXTERNAL_STORAGE)
}
if (isGranted == PackageManager.PERMISSION_GRANTED) {
downloadImage() //Call the download method
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//In a fragment, simply use requestPermissions() instead of ActivityCompat.requestPermission()
requestPermissions(arrayOf(permissionType),
WRITE_EXTERNAL_STORAGE_RC)
}
}
}
Call onRequestPermissionResult() function
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode,
permissions, grantResults)
when (requestCode) {
WRITE_EXTERNAL_STORAGE_RC -> {
//If the Android version is higher than Marshmallow, request user permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
grantResults.isEmpty() || grantResults[0] !=
PackageManager.PERMISSION_GRANTED) {
Timber.d("Permission denied by user")
} else {
downloadImage()//Call the download method again
Timber.d("Permission granted by user")
}
}
}
}