Preparing for Scoped Storage
- Le Memeify 👌
- Getting Started
- Understanding the Project Structure
- Running Le Memeify
- Grokking Scoped Storage
- Running on Android 10
- Targeting Android 11
- Updating to Support Scoped Storage
- Loading the Images
- Creating a New File
- Changing File IO to URIs
- Creating a New File in a Specific Location
- Updating an Existing Image
- Handling the Permission Request
- Deleting an Image
- Where to Go From Here?
Android 10 put a greater emphasis on privacy and security. Android 11 continues this emphasis and gives you many tools to achieve this. One of those tools is scoped storage. This feature impacts your app in a big way if you’re leveraging local file access.
With scoped storage, an app no longer has direct access to all the files in external storage. If an app wants to manipulate a file that it didn’t create, it has to get explicit authorization from the user. These request prompts appear for each file. This provides a new level of control for the user. They can now decide what an app can or cannot do with their files.
Because this can have a potentially heavy impact on existing apps, Android 10 provides an opt-out mechanism. When enabled, it allows an app to work without any of these requirements. The caveat here is that when your app targets API 30 (Android 11), scoped storage starts to be mandatory.
So if your app uses device storage, it’s time to start preparing it for scoped storage.
Le Memeify 👌
To learn more about scoped storage, you’ll work on a meme app. You’ll learn a lot and have fun along the way!
The app you’ll work on is called, “Le Memeify”. This app has a built-in interface that allows you to create, edit or delete a meme from any image on your device.
Feel free to share your best memes with your friends. :]
Access the tutorial files by clicking on Download Materials at the top or bottom of this tutorial. You’ll find two projects inside the zip file: Starter has the skeleton of the app you’ll build. And Final gives you something to compare your code to when you’re done.
This is what you’re going to build! You already have a whole gallery of memes in the app but feel free to download others. Here’s a website you can use: imgflip.
The goal of this article is to show you how to prepare your app for scoped storage.
There are different ways to do this. The first way you’ll see is in the Starter project which uses file paths to access images and stores them in external storage.
The other way is to follow scoped storage requirements. This method requests user access to manipulate files that weren’t created by the app. If granted, it uses URIs to access those files. Also, it stores new images inside the Pictures folder per Google’s recommendation.
Ready to dive in?
Understanding the Project Structure
Open the Starter project in Android Studio and wait for it to synchronize. Take a look at the project directory structure:
You’ll see a set of subfolders and important files:
- model: This is the data object used to represent an image. It contains the file path, creation date, timestamp, size, etc.
- ui: In this folder, you’ll find the activity, fragments, view models and adapters you’ll use to allow your users to view and interact with the app’s data. This folder also has two subfolders for the two main screens of the app: details and images.
- ui/actions.kt: Here you’ll find the Kotlin sealed classes for any action a view might take. This makes things nice and tidy by explicitly listing these actions.
- FileOperations.kt: This file contains the class that defines all the file operations.
- Utils.kt: This file has the set of utility methods you’ll use throughout the project.
Running Le Memeify
In order to access the images on your device, you must grant the storage permission when prompted. Otherwise, you’ll see a toast with the message:
- “You need to grant media permissions to use the app”.
Build and run the app. After you accept the permissions, you’ll see a screen like this:
…with different images, of course. :]
Grokking Scoped Storage
Scoped storage addresses several issues with the Android file system. Namely, it aims to better define which files a third-party app can access, where to store files needed or created by the app and what to do with them after the user uninstalls the app.
Before you start building this app, think about the two different types of storage a device has:
- App-specific: internal storage: Only the app itself can access the files in this directory, known as the “app sandbox”. Because of this, you don’t need to declare the storage permission in the manifest file. Also, no third-party apps can access its content so it’s a good place to store sensitive information. And when the user uninstalls the app, the system deletes the directory.
- External storage: This is the non-internal space on the user’s disk. It can include an external drive, like an SD Card. The system will not delete data here when the user uninstalls the app. As such, the user can end up with unused files that only take up space.
With these limitations, Android more strictly controls where an app can store files. It can be either of the following:
- App-specific: external storage: This storage differs from internal storage in that there’s no pre-allocated space for it in the sandbox. The available storage for saving is equal to the disk’s remaining space. But it’s like internal storage in that you don’t need to declare writing permissions and the system will delete all its files when the user uninstalls the app.
- External storage: This storage includes access to the device gallery through the MediaStore API. To view/edit other files, you need to use the system file picker called through the Storage Access Framework or SAF.
You’ll need to request two permissions for this if the app is targeting Android 9 or Android 10 with legacy mode enabled:
Newer versions only require