Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getExternalStoragePublicDirectory deprecated in Android Q

Tags:

android

As getExternalStoragePublicDirectory has been deprecated in Android Q, and the recommendation is to use other means. then how can we specify that we want to store the generated photos from a camera app into the DCIM folder, or a custom sub-folder within the DCIM?

The documentation states that the next 3 options are the new preferred alternatives:

  1. Context#getExternalFilesDir(String)
  2. MediaStore
  3. Intent#ACTION_OPEN_DOCUMENT

Option 1 is out of the questions as it would mean that the photos get deleted if the app gets uninstalled.

Option 3 is also not a choice, as it would require the user to pick the location through the SAF file explorer.

We are left with option 2, the MediaStore; but at the time of this question there is no documentation on how to use it as a replacement for getExternalStoragePublicDirectory in Android Q.

like image 869
PerracoLabs Avatar asked Jun 05 '19 21:06

PerracoLabs


People also ask

What is getExternalStoragePublicDirectory?

getExternalStoragePublicDirectory gives internal storage - Stack Overflow. Stack Overflow for Teams – Start collaborating and sharing organizational knowledge.

What is Media_mounted?

MEDIA_MOUNTED. Storage state if the media is present and mounted at its mount point with read/write access. String. MEDIA_MOUNTED_READ_ONLY. Storage state if the media is present and mounted at its mount point with read-only access.

Where is Getexternalfilesdir?

It returns the path to files folder inside Android/data/data/your_package/ on your SD card. It is used to store any required files for your app (e.g. images downloaded from web or cache files).


2 Answers

Based on the docs, use DCIM/... for the RELATIVE_PATH, where ... is whatever your custom subdirectory would be. So, you would wind up with something like this:

      val resolver = context.contentResolver       val contentValues = ContentValues().apply {         put(MediaStore.MediaColumns.DISPLAY_NAME, "CuteKitten001")         put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")         put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/PerracoLabs")       }        val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)        resolver.openOutputStream(uri).use {         // TODO something with the stream       } 

Note that since RELATIVE_PATH is new to API Level 29, you would need to use this approach on newer devices and use getExternalStoragePublicDirectory() on older ones.

like image 89
CommonsWare Avatar answered Oct 02 '22 11:10

CommonsWare


@CommonsWare answer is amazing. But for those who want it in Java, you need to try this:

ContentResolver resolver = context.getContentResolver(); ContentValues contentValues = new ContentValues(); contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name); contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType); contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);  Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues); 

As per the suggestion of @SamChen the code should look like this for text files:

Uri uri = resolver.insert(MediaStore.Files.getContentUri("external"), contentValues); 

Because we wouldn't want txt files lingering in the Images folder.

So, the place where I have mimeType, you enter the mime type you want. For example if you wanted txt (@Panache) you should replace mimeType with this string: "text/plain". Here is a list of mime types: https://www.freeformatter.com/mime-types-list.html

Also, where I have the variable name, you replace it with the name of the file in your case.

like image 22
Gaurav Mall Avatar answered Oct 02 '22 12:10

Gaurav Mall