Google is committed to advancing racial equity for Black communities. See how.

Android storage use cases and best practices

To give users more control over their files and limit file clutter, Android 10 introduced a new storage paradigm for apps called scoped storage. Scoped storage changes the way apps store and access files on a device's external storage. To help you migrate your app to support scoped storage, follow the best practices for common storage use cases that are outlined in this guide. The use cases are organized into two categories: handling media files and handling non-media files.

To learn more about how to store and access files on Android, see the storage training guides.

Handle media files

This section describes some of the common use cases for handling media files (video, image, and audio files) and explains the high-level approach that your app can use. The following table summarizes each of these use cases, and links to the each of sections that contain further details.

Use case Summary
Show all image or video files Use the same approach for all versions of Android.
Show images or videos from a particular folder Use the same approach for all versions of Android.
Access location information from photos Use one approach if your app uses scoped storage. Use a different approach if your app opts out of scoped storage.
Modify or delete multiple media files in a single operation Use one approach for Android 11. For Android 10, opt out of scoped storage and use the approach for Android 9 and lower instead.
Import a single image that already exists Use the same approach for all versions of Android.
Capture a single image Use the same approach for all versions of Android.
Share media files with other apps Use the same approach for all versions of Android.
Share media files with a specific app Use the same approach for all versions of Android.
Access files from code or libraries that use direct file paths Use one approach for Android 11. For Android 10, opt out of scoped storage and use the approach for Android 9 and lower instead.

Show image or video files from multiple folders

Query a media collection using the query() API. To filter or sort the media files, adjust the projection, selection, selectionArgs, and sortOrder parameters.

Show images or videos from a particular folder

Use this approach:

  1. Following the best practices outlined in Request App Permissions, request the READ_EXTERNAL_STORAGE permission.
  2. Retrieve media files based on the value of MediaColumns.DATA, which contains the absolute filesystem path to the media item on disk.

Access location information from photos

If your app uses scoped storage, follow the steps in the Location information in photographs section of the media storage guide.

Modify or delete multiple media files in a single operation

Incorporate logic based on the Android versions that your app runs on.

Running on Android 11

Use this approach:

  1. Create a pending intent for your app's write or delete request using MediaStore.createWriteRequest() or MediaStore.createTrashRequest() and then prompt the user for permission to edit a set of files by invoking that intent.
  2. Evaluate the user's response:

    • If the permission was granted, proceed with the modify or delete operation.
    • If the permission wasn't granted, explain to the user why the feature in your app needs the permission.

Learn more about how to perform batch operations using these methods that are available in Android 11.

Running on Android 10

If your app targets Android 10 (API level 29), opt-out of scoped storage and continue using the approach for Android 9 and lower to perform this operation.

Running on Android 9 or lower

Use this approach:

  1. Following the best practices outlined in Request App Permissions, request the WRITE_EXTERNAL_STORAGE permission.
  2. Use the MediaStore API to modify or delete the media files.

Import a single image that already exists

When you want to import a single image that already exists (for example, to use as the photo for a user's profile), your app can either use its own UI for the operation, or it can use the system picker.

Present your own user interface

Use this approach:

  1. Following the best practices outlined in Request App Permissions, request the READ_EXTERNAL_STORAGE permission.
  2. Use the query() API to query a media collection.
  3. Display the results in your app's custom UI.

Use the system picker

Use the ACTION_GET_CONTENT intent, which asks the user to pick an image to import.

If you want to filter the types of images that the system picker presents to the user to choose from, you can use setType() or EXTRA_MIME_TYPES.

Capture a single image

When you want to capture a single image to use in your app (for example, to use as the photo for a user's profile), use the ACTION_IMAGE_CAPTURE intent to ask the user to take a photo using the device's camera. The system stores the captured photo in the MediaStore.Images table.

Share media files with other apps

Use the insert() method to add records directly into the MediaStore. For more information, see the Add an item section of the media storage guide.

Share media files with a specific app

Use the Android FileProvider component, as described in the Setting up file sharing guide.

Access files from code or libraries that use direct file paths

Incorporate logic based on the Android versions that your app runs on.

Running on Android 11

Use this approach:

  1. Following the best practices outlined in Request App Permissions, request the READ_EXTERNAL_STORAGE permission.
  2. Access the files using direct file paths.

For more information, see Access files using raw paths.

Running on Android 10

If your app targets Android 10 (API level 29), opt-out of scoped storage and continue using the approach for Android 9 and lower to perform this operation.

Running on Android 9 or lower

Use this approach:

  1. Following the best practices outlined in Request App Permissions, request the WRITE_EXTERNAL_STORAGE permission.
  2. Access the files using direct file paths.

Handle non-media files

This section describes some of the common use cases for handling non-media files and explains the high-level approach that your app can use. The following table summarizes each of these use cases, and links to the each of sections that contain further details.

Use case Summary
Open a document file Use the same approach for all versions of Android.
Migrate existing files from a legacy storage location Migrate your files to scoped storage when possible. Opt out of scoped storage for Android 10 when necessary.
Share content with other apps Use the same approach for all versions of Android.
Cache non-media files Use the same approach for all versions of Android.

Open a document file

Use the ACTION_OPEN_DOCUMENT intent to ask the user to pick a file to open using the system picker. If you want to filter the types of files that the system picker will present to the user to choose from, you can use setType() or EXTRA_MIME_TYPES.

For example, you could find all PDF, ODT, and TXT files using the following code:

Kotlin

startActivityForResult(
        Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = "*/*"
            putExtra(Intent.EXTRA_MIME_TYPES, arrayOf(
                    "application/pdf", // .pdf
                    "application/vnd.oasis.opendocument.text", // .odt
                    "text/plain" // .txt
            ))
        },
        REQUEST_CODE
      )

Java

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {
                "application/pdf", // .pdf
                "application/vnd.oasis.opendocument.text", // .odt
                "text/plain" // .txt
        });
        startActivityForResult(intent, REQUEST_CODE);

Migrate existing files from a legacy storage location

A directory is considered a legacy storage location if it isn't an app-specific directory or a public shared directory. If your app creates or consumes files in a legacy storage location, we recommend that you migrate your app's files to locations that are accessible with scoped storage and make any necessary app changes to work with files in scoped storage.

Maintain access to the legacy storage location for data migration

Your app needs to maintain access to the legacy storage location in order to migrate any app files to locations that are accessible with scoped storage. The approach you should use depends on your app’s target API level.

If your app targets Android 11
  1. Use the preserveLegacyExternalStorage flag to preserve the legacy storage model so that your app can migrate a user's data when they upgrade to the new version of your app that targets Android 11.

  2. Continue to opt out of scoped storage so that your app can continue to access your files in the legacy storage location on Android 10 devices.

If your app targets Android 10

Opt out of scoped storage to make it easier to maintain your app's behavior across Android versions.

Migrate app data

When your app is ready to migrate, use the following approach:

  1. Target Android 10 or lower.
  2. Opt out of scoped storage so that your app has access to the files that you need to migrate.
  3. Deploy code that uses the File API to move files from their current location under /sdcard/ to a location that's accessible with scoped storage:

    1. Move any private app files to the directory that is returned by the getExternalFilesDir() method.
    2. Move any shared non-media files to an app-dedicated subdirectory of the Downloads/ directory.
  4. Remove your app's legacy storage directories from the /sdcard/ directory.

After users install the new version of your app, they complete the data migration process on their devices. You can monitor the migration process across your user base by creating an analytics event.

After users have migrated their data, publish another update to your app, where you target Android 11.

Share content with other apps

To share your app's files with a single other app, use a FileProvider. For apps that all need to share files between each other, we recommend using a content provider for each app, and then syncing the data as apps are added to the collection.

Cache non-media files

The approach that you should use depends on the type of files that you need to cache.

Temporarily opt-out of scoped storage

Before your app is fully compatible with scoped storage, you can temporarily opt out by using one of the following methods:

  • Target Android 9 (API level 28) or lower.
  • If you target Android 10 (API level 29) or higher, set the value of requestLegacyExternalStorage to true in your app's manifest file:

    <manifest ... >
    <!-- This attribute is "false" by default on apps targeting
         Android 10 or higher. -->
      <application android:requestLegacyExternalStorage="true" ... >
        ...
      </application>
    </manifest>
    

To test how an app targeting Android 9 or lower behaves when using scoped storage, you can opt in to the behavior by setting the value of requestLegacyExternalStorage to false. If you are testing on an Android 11 device, you can also use app compatibility flags to test your app's behavior with or without scoped storage.