I am saving a file inside the Downloads
directory of the device (Android 11)
to be viewed later by my app. I'm allowing multiple file types like pdf
, word
etc. I was able to save the file like this: (I got this code sample from here )
@TargetApi(29)
private suspend fun downloadQ(
url: String,
filename: String,
mimeType: String
) =
withContext(Dispatchers.IO) {
val response = ok.newCall(Request.Builder().url(url).build()).execute()
if (response.isSuccessful) {
val values = ContentValues().apply {
put(MediaStore.Downloads.DISPLAY_NAME, filename)
put(MediaStore.Downloads.MIME_TYPE, mimeType)
put(MediaStore.Downloads.IS_PENDING, 1)
}
val resolver = context.contentResolver
val uri =
resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values)
uri?.let {
resolver.openOutputStream(uri)?.use { outputStream ->
val sink = outputStream.sink().buffer()
response.body()?.source()?.let { sink.writeAll(it) }
sink.close()
}
values.clear()
values.put(MediaStore.Downloads.IS_PENDING, 0)
resolver.update(uri, values, null, null)
} ?: throw RuntimeException("MediaStore failed for some reason")
} else {
throw RuntimeException("OkHttp failed for some reason")
}
}
But when I tried to retrieve the file, I tried with the following ways that did not work:
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID)
val id = cursor.getLong(idColumn)
Log.d("uri id ","$id")
val contentUri = ContentUris.withAppendedId(MediaStore.Downloads.EXTERNAL_CONTENT_URI,id)
This approach threw an exception:
java.lang.IllegalArgumentException: Failed to find configured root that contains /external/downloads/78
I got this ID
(here 78) from the query
and cursor
from ContentResolver.query()
and I hoped it to return the Uri
from which I could get the File.
The second approach was this:
val uri = MediaStore.Downloads.getContentUri("external",id)
uri.path?.let { filePath ->
Log.d("uri path ",filePath)
val file = File(filePath)
} ?: Log.d("uri path ","null")
I used external
as the directory based on this answer, but this approach also threw the same exception
java.lang.IllegalArgumentException: Failed to find configured root that contains /external/downloads/78
At the end what ended up working was hardcoding something like this after I used a file explorer app to view the exact directory path:
val file = File("storage/emulated/0/Download/$name.$extension")
So my question is, how do I get the value of this path dynamically, and is this path the same for all devices that can be used like this way?
EDIT: I also wanted to know if I am using the filename
and it's extension
to view the file, then if user downloads another file with same name then how do I make sure that correct file is opened? (even if i make a separate directory for my app inside Download
, user could still download the same file twice that has a name like storage/emulated/0/Download/myDir/file(2).extension
)
Try with the following code it will help you.
private fun readFile(){
val FILENAME = "user_details.txt"
val dir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
.toString() + "/" + "folderName"
)
} else {
File(
Environment.getExternalStorageDirectory()
.toString() + "/${Environment.DIRECTORY_DOWNLOADS}/" + "folderName"
)
}
dir.apply {
if(this.exists()) File(this, FILENAME).apply {
FileInputStream(this).apply {
val stringBuffer = StringBuffer()
var i: Int
while (this.read().also { i = it } != -1) {
stringBuffer.append(i.toChar())
}
close()
}
}
}
}
You can use
{Environment.DIRECTORY_DOWNLOADS} + "/folderName/file_name.mime_type"
/storage/emulated/0/Download/12d82c65-00a5-4c0a-85bc-238c28005c33.bin
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.