getExternalStoragePublicDirectory deprecated in Android Q
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.
Environment.getExternalStorageDirectory() deprecated in API level 29 java
Use getExternalFilesDir()
, getExternalCacheDir()
, or getExternalMediaDirs()
(methods on Context
) instead of Environment.getExternalStorageDirectory()
.
Or, modify mPhotoEditor
to be able to work with a Uri
, then:
Use
ACTION_CREATE_DOCUMENT
to get aUri
to a location of the user's choosing, orUse
MediaStore
,ContentResolver
, andinsert()
to get aUri
for a particular type of media (e.g., an image) — see this sample app that demonstrates doing this for downloading MP4 videos from a Web site
Also, note that your Uri.fromFile
with ACTION_MEDIA_SCANNER_SCAN_FILE
should be crashing on Android 7.0+ with a FileUriExposedException
. On Android Q, only the MediaStore
/insert()
option will get your content indexed by the MediaStore
quickly.
Note that you can opt out of these "scoped storage" changes on Android 10 and 11, if your targetSdkVersion
is below 30, using android:requestLegacyExternalStorage="true"
in the <application>
element of the manifest. This is not a long-term solution, as your targetSdkVersion
will need to be 30 or higher sometime in 2021 if you are distributing your app through the Play Store (and perhaps elsewhere).
How to read or write file as getExternalStorageDirectory is deprecated in API 29?
From the docs you can see:
getExternalStoragePublicDirectory(String type)
This method was deprecated in API level 29. To improve user privacy, direct access to shared/external storage devices is deprecated. When
an app targets Build.VERSION_CODES.Q, the path returned from this
method is no longer directly accessible to apps. Apps can continue to
access content stored on shared/external storage by migrating to
alternatives such as Context#getExternalFilesDir(String),
MediaStore, or Intent#ACTION_OPEN_DOCUMENT.
Pass nothing as parameter to this function to get your directory as a File
object :
context.getExternalFilesDir();
Here "Context" is an object which is obtained by this.getContext();
this
is the current object of the Activity. Do check the scope carefully while using it.
Important
To access the Internal storage, Manifest.permission.WRITE_EXTERNAL_STORAGE
and/or Manifest.permission.READ_EXTERNAL_STORAGE
are required in the file AndroidManifest.xml.
Optional information:
Usually the internal storage has the path
/sdcard/ on Android devices. It's not a real path but a symlink.It's confusing but "external sdcard" in Android acutally means the Internal device storage and not the external ejectable out-of-the-device memory card storage.
Also note that the real external sdcard cannot be fully accessActivity class extends the Context class That's why we can get the context from it.
Related Topics
Arrayadapter in Android to Create Simple Listview
Android Plugin Install Problems in Eclipse
No Shadow by Default on Toolbar
Android Listview Refresh Single Row
Error Message 'Java.Net.Socketexception: Socket Failed: Eacces (Permission Denied)'
Using the Recyclerview with a Database
Android Webview Not Loading an Https Url
Selecting Multiple Items in Listview
How to Add Java.Awt.Image Package in Android
Notification Click: Activity Already Open
How to Add a Badge to an Application Icon in Android
Do X86 Android Avd's Work on Linux on Amd
What Is the Size of Actionbar in Pixels
How to Marshall and Unmarshall a Parcelable to a Byte Array with Help of Parcel
Remove Listview Items in Android
What Is "Android.R.Layout.Simple_List_Item_1"
How to Programmatically Turn Off Wifi on Android Device
Android: How to Make a Clickable Map Image with Each Country Producing a Different Action