- Android 11 storage FAQ
- Does Scoped Storage allow apps to access files with file paths, using File API, for example?
- How does the performance of file path access compare to Media Store APIs?
- My app needs broad access to shared storage. Is Storage Access Framework the only option available?
- What categories of apps should request the MANAGE_EXTERNAL_STORAGE permission?
- Does using Storage Access Framework require Google Play policy approval?
- Are there any further restrictions to using Storage Access Framework in Android 11 as compared to Android 10?
- How can apps test out Scoped Storage changes?
- Are apps in scoped storage limited to writing files into their app-specific data directories?
- What is the guidance around using the Media Store DATA column since it’s been deprecated?
- For apps that have opted out of Scoped Storage, when will they have to be compatible with Scoped Storage?
- What is the recommended way to migrate data that we currently store outside of Scoped Storage?
- Are there any exceptions for Android/obb directories given that some package installers, like app stores, need access to it?
- Data and file storage overview
- Categories of storage locations
- Permissions and access to external storage
- Scoped storage
- View files on a device
- Additional resources
- Videos
- How to write text data to files in Android: Build a ScratchPad (memo) App
- Building the interface of the scratchpad app in Android
- Widgets Required
- Creating the layout using XML
- Changing the colours of the App
- Coding the actual functionality of our Scratchpad app
- Adding widgets to the code
- How to handle file input and output operations in Android
- Writing to a private .txt file in Android
- Reading from a private .txt file in Android
- Code explanation
- Implementing the save functionality
- Testing the Scratchpad App
- How to view the contents of a private .txt file in Android?
- Complete Code for the Scratchpad App
- activity_main.xml
- colors.xml
- Java File
- Leave a Reply Cancel reply
Android 11 storage FAQ
First introduced in Android 10, scoped storage is designed to protect app and user data and reduce file clutter. Since then, you’ve provided a lot of valuable feedback, which has helped us evolve the feature — thank you. Android 11 includes several notable enhancements that are based on your feedback. For example, we’ve enabled direct file path access to media files to improve compatibility of existing code and libraries. We understand that many apps, especially complex ones like Viber, require thoughtful planning to adopt scoped storage in order to continue supporting existing users, ensure adherence to current storage best practices, and maintain backward compatibility. Based on conversations with developers and lively discussions on public forums, we’ve prepared an FAQ to help you better understand various capabilities, behavior changes, and restrictions in scoped storage.
Does Scoped Storage allow apps to access files with file paths, using File API, for example?
- We recognize that some apps rely on code or libraries that access media file paths directly. Therefore on Android 11, apps with the read external storage permission are able to access files with file paths in the scoped storage environment. On Android 10 devices, this is not available to apps in the scoped storage environment unless they have opted-out by setting the android:requestLegacyExternalStorage manifest attribute. To ensure continuity across Android versions, if your app targets Android 10 or above, you should also opt-out. See scoped storage best practices for details.
How does the performance of file path access compare to Media Store APIs?
- The performance really depends on the exact use case. For sequential reads like in the case of playback of videos, file path access offers comparable performance to Media Store. However for random reads and writes, using file path can be up to twice as slow. For the fastest and most consistent read and writes we recommend Media Store APIs.
My app needs broad access to shared storage. Is Storage Access Framework the only option available?
- Storage Access Framework (SAF) is indeed one option that allows the user to grant access to directories and files. However, note that there are access restrictions to certain directories, such as the root and Android/data directories. While the majority of apps that need storage access can use best practices such as SAF or Media Store API, there could be cases where apps need broad access to shared storage or can’t do so efficiently with these best practices. For these cases, we have added the MANAGE_EXTERNAL_STORAGE permission to give access to all files on external storage, except the Android/data and Android/obb directories. To learn more about related Google Play guidelines, read the updated policy from the Policy Help Center.
What categories of apps should request the MANAGE_EXTERNAL_STORAGE permission?
- The MANAGE_EXTERNAL_STORAGE permission is intended for apps that have a core use case that requires broad access of files on a device, but cannot do so efficiently using scoped storage best practices. While it isn’t practical to enumerate all possible use cases, some use cases include file managers, backup and restore, anti-virus apps or productivity file editing apps.
Does using Storage Access Framework require Google Play policy approval?
- The Storage Access Framework has been in the platform since Android 4.4. Accessing files via Storage Access Framework gives users better control because the user is involved in picking files and it doesn’t require any user permissions. There’s no Google Play policy related to its usage.
Are there any further restrictions to using Storage Access Framework in Android 11 as compared to Android 10?
- Apps that target Android 11 (API level 30) and use Storage Access Framework will no longer be able to grant access to directories, such as the root directory of the SD card and the Download directory. Regardless of target SDK, Storage Access Framework on Android 11 cannot be used to gain access to Android/data and Android/obb directories. Learn more about these restrictions and ways to test the behaviors.
How can apps test out Scoped Storage changes?
- Apps can test out scoped storage behavior related to direct file path access or Media Store APIs via these compatibility flags. There’s also another compatibility flag to test the restrictions to access certain paths with Storage Access Framework.
Are apps in scoped storage limited to writing files into their app-specific data directories?
- In scoped storage, apps can contribute media files to Media Store collections. Media Store will put the files into well organized folders like DCIM, Movies, Download, and so on based on file type. For all such files, apps can also continue to have access via File APIs as well. The OS maintains a system to attribute an app to each media store file, so apps can read/write files that they originally contributed to the Media Store without needing storage permissions.
What is the guidance around using the Media Store DATA column since it’s been deprecated?
- On Android 10, apps in the scoped storage environment cannot access files using the file path. To be consistent with this design, we deprecated the DATA column then. Based on your feedback on the needs to work with existing native code or libraries, Android 11 now supports file path access for apps in scoped storage. Accordingly, the DATA column could actually be useful for some scenarios. For inserts and updates into the Media Store, apps in Scoped Storage should use DISPLAY_NAME and RELATIVE_PATH columns. They can no longer use the DATA column for this. When reading Media Store entries for files that exist on disk, the DATA column will have a valid file path, which can be used with the File API or NDK file libraries. Apps should however be prepared to handle any file I/O errors from these operations and should not assume the file is always available.
For apps that have opted out of Scoped Storage, when will they have to be compatible with Scoped Storage?
- On devices running Android 11 or higher, apps will be put into Scoped Storage as soon as they target Android 11 or higher.
What is the recommended way to migrate data that we currently store outside of Scoped Storage?
- preserveLegacyExternalStorage flag allows an app to retain legacy storage access on upgrades even while targeting Android 11. However beware that on new installs on Android 11, this flag has no effect. Please make code changes to adapt to Scoped Storage before targeting Android 11. Learn more about data migration best practices.
Are there any exceptions for Android/obb directories given that some package installers, like app stores, need access to it?
- Apps that hold the REQUEST_INSTALL_PACKAGES permission can access other apps’ Android/obb directories.
We hope you find this FAQ useful in planning your adoption of scoped storage. Please visit our best practice documentation for more information.
Источник
Data and file storage overview
Android uses a file system that’s similar to disk-based file systems on other platforms. The system provides several options for you to save your app data:
- App-specific storage: Store files that are meant for your app’s use only, either in dedicated directories within an internal storage volume or different dedicated directories within external storage. Use the directories within internal storage to save sensitive information that other apps shouldn’t access.
- Shared storage: Store files that your app intends to share with other apps, including media, documents, and other files.
- Preferences: Store private, primitive data in key-value pairs.
- Databases: Store structured data in a private database using the Room persistence library.
The characteristics of these options are summarized in the following table:
Type of content | Access method | Permissions needed | Can other apps access? | Files removed on app uninstall? | |
---|---|---|---|---|---|
App-specific files | Files meant for your app’s use only | From internal storage, getFilesDir() or getCacheDir() From external storage, getExternalFilesDir() or getExternalCacheDir() | Never needed for internal storage Not needed for external storage when your app is used on devices that run Android 4.4 (API level 19) or higher | No | Yes |
Media | Shareable media files (images, audio files, videos) | MediaStore API | READ_EXTERNAL_STORAGE when accessing other apps’ files on Android 11 (API level 30) or higher READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE when accessing other apps’ files on Android 10 (API level 29) Permissions are required for all files on Android 9 (API level 28) or lower | Yes, though the other app needs the READ_EXTERNAL_STORAGE permission | No |
Documents and other files | Other types of shareable content, including downloaded files | Storage Access Framework | None | Yes, through the system file picker | No |
App preferences | Key-value pairs | Jetpack Preferences library | None | No | Yes |
Database | Structured data | Room persistence library | None | No | Yes |
The solution you choose depends on your specific needs:
How much space does your data require? Internal storage has limited space for app-specific data. Use other types of storage if you need to save a substantial amount of data. How reliable does data access need to be? If your app’s basic functionality requires certain data, such as when your app is starting up, place the data within internal storage directory or a database. App-specific files that are stored in external storage aren’t always accessible because some devices allow users to remove a physical device that corresponds to external storage. What kind of data do you need to store? If you have data that’s only meaningful for your app, use app-specific storage. For shareable media content, use shared storage so that other apps can access the content. For structured data, use either preferences (for key-value data) or a database (for data that contains more than 2 columns). Should the data be private to your app? When storing sensitive data—data that shouldn’t be accessible from any other app—use internal storage, preferences, or a database. Internal storage has the added benefit of the data being hidden from users.
Categories of storage locations
Android provides two types of physical storage locations: internal storage and external storage. On most devices, internal storage is smaller than external storage. However, internal storage is always available on all devices, making it a more reliable place to put data on which your app depends.
Removable volumes, such as an SD card, appear in the file system as part of external storage. Android represents these devices using a path, such as /sdcard .
Apps themselves are stored within internal storage by default. If your APK size is very large, however, you can indicate a preference within your app’s manifest file to install your app on external storage instead:
Permissions and access to external storage
On earlier versions of Android, apps needed to declare the READ_EXTERNAL_STORAGE permission to access any file outside the app-specific directories on external storage. Also, apps needed to declare the WRITE_EXTERNAL_STORAGE permission to write to any file outside the app-specific directory.
More recent versions of Android rely more on a file’s purpose than its location for determining an app’s ability to access, and write to, a given file. In particular, if your app targets Android 11 (API level 30) or higher, the WRITE_EXTERNAL_STORAGE permission doesn’t have any effect on your app’s access to storage. This purpose-based storage model improves user privacy because apps are given access only to the areas of the device’s file system that they actually use.
Android 11 introduces the MANAGE_EXTERNAL_STORAGE permission, which provides write access to files outside the app-specific directory and MediaStore . To learn more about this permission, and why most apps don’t need to declare it to fulfill their use cases, see the guide on how to manage all files on a storage device.
Scoped storage
To give users more control over their files and to limit file clutter, apps that target Android 10 (API level 29) and higher are given scoped access into external storage, or scoped storage, by default. Such apps have access only to the app-specific directory on external storage, as well as specific types of media that the app has created.
Use scoped storage unless your app needs access to a file that’s stored outside of an app-specific directory and outside of a directory that the MediaStore APIs can access. If you store app-specific files on external storage, you can make it easier to adopt scoped storage by placing these files in an app-specific directory on external storage. That way, your app maintains access to these files when scoped storage is enabled.
To prepare your app for scoped storage, view the storage use cases and best practices guide. If your app has another use case that isn’t covered by scoped storage, file a feature request. You can temporarily opt-out of using scoped storage.
View files on a device
To view the files stored on a device, use Android Studio’s Device File Explorer.
Additional resources
For more information about data storage, consult the following resources.
Videos
Content and code samples on this page are subject to the licenses described in the Content License. Java is a registered trademark of Oracle and/or its affiliates.
Источник
How to write text data to files in Android: Build a ScratchPad (memo) App
What will you learn?
In this simple app, you will learn how to enter a string of text into a file and save it using a button. Next time you open the app, it will still be there.
You will also learn the concept of file handling in Android. File Handling is one of the methods to make your data ‘persist’. This saves your data to a file so that it exists even after the app is closed.
The classes and methods you will learn in this are:
- OutputStreamWriter
- InputStreamReader
- openFileInput()
- openFileOutput()
Note: Find the full code of this scratchpad project towards the end of the post. Read the entire post for further clarification and explanations.
Building the interface of the scratchpad app in Android
In this app, we’ll be working with a single activity. Let’s move forward to the designing part. As you might have observed earlier, the designing part of an activity is done using XML. Don’t worry if you don’t know XML. Android Studio provides an intuitive drag and drop interface to design app visuals. I’ll be illustrating the code part of it since it is easy to explain in a textual tutorial.
Widgets Required
This is a pretty straightforward app that allows the user to write something down and save it. So we just require two widgets:
- EditText
- Button
- The EditText allows the user to enter text input.
- The Button will be used to save the text in a txt file. If the txt file doesn’t exist, then we will create it.
Creating the layout using XML
Open up the activity_main.xml file, and head over to the Text tab (bottom left corner).
You’ll see the following default code:
Now we’ll add the widgets in between the android tag.
First, the EditText. Ideally, it should be big and have lots of space since it is the main part of our app. Write down the following:
Now, for the Button, add the following code right after the EditText code.:
We’ve added two widgets: EditText and Button. EditText allows the user to enter text input; it could be anything – email, password, numeric input etc.
Button provides a clickable interface for performing certain actions.
You’ll observe a lot of attributes here, here is a description of what they do:
- constraintBottom, constraintTop etc. : These attributes are specific to elements in a ConstraintLayout. Basically, they are used to set the constraints (boundaries), positioning of elements relative to each other. If you don’t remember the layouts, then it is highly recommended that you read about the different layouts in Android.
- marginLeft, marginRight, etc.: They are used to set the margins for the element.
- layout_width, layout_height: They are used to set the size (height and width) of the element. wrap_content is used to indicate that the size should be adjusted as per the content (text, image, etc.) of the element.
- hint: The hint attribute is used in EditText to add a placeholder. It lets the user know that that’s a clickable field.
- ID: This is used to give a unique identifier to the widget; this is important as it is used to reference these widgets in the Java code. Remember, the Java code has no knowledge of this XML code by default; we need to set it up so that it can recognize elements.
- inputType: Specifies the type of input (email, password, numeric, etc.) in the EditText. We have set the inputType attribute of the EditText to ‘textMultiLine’; this will allow the user to input multiple lines of text.
The end result of the above few lines of code will look like this: This is what the app would look like
Changing the colours of the App
Additionally, let’s change the colours to the app, these will be visible on the title bar when we run the app, and when the EditText is selected. Head over to res/values/colors.xml. Location of the colors.xml file
Replace the default code with the following:
Coding the actual functionality of our Scratchpad app
Now we’ll get down to the actual coding part. Open up the MainActivity.java file.
Adding widgets to the code
Let’s start adding our widgets to the code. Write the following code inside the main function before the onCreate() function. If you gave it a name other than MainActivity, that will be the main function:
Now we’ll reference the actual widgets from the XML file. Write this below setContentView(R.layout.activity_main); inside onCreate() function.
Remember the IDs we had assigned to the widgets in the XML file? They are used here, to connect the Java code to the XML code components. This will set up our widgets.
How to handle file input and output operations in Android
Now, we’ll define two methods to read and write data to files: readFromFile() and writeToFile().
As the name suggests, readFromFile() will be used to read the data from the file, and writeToFile() will be used to write to the file. If the file doesn’t exist, writeToFile() also creates the file in the memory.
The File that we have been talking about will be a .txt file in private mode so that only this App can access it. The code is as follows:
Writing to a private .txt file in Android
We create a new function and assign it a name. In this particular tutorial, we have given it the name writeToFile(). The code for this goes right after the onCreate() function is closed.
Reading from a private .txt file in Android
After we have written code for writing to a file, we will write the code to read from the .txt file. This is how it goes down:
Code explanation
- The file that we are reading from and writing to is ‘todolist.txt’. The methods openFileInput() and openFileOutput() are used to open the file for reading and writing, respectively.
- The method openFileOutput() has the following signature: public abstract FileOutputStream openFileOutput (String name, int mode), where name is a String indicating the file name and mode is an Integer flag that indicates how the file should be opened. This method opens a file for writing and creates a new file if it doesn’t exist. The different modes are as follows:
MODE_PRIVATE: The default mode, where the created file can only be accessed by the calling application (or all applications sharing the same user ID).
MODE_WORLD_READABLE: (Deprecated) Allows all other applications to have read access to the created file.
MODE_WORLD_WRITEABLE: (Deprecated) Allows all other applications to have write access to the created file.
MODE_APPEND: If the file already exists then write data to the end of the existing file instead of erasing it.
- In these methods, we use OutputStreamWriter and InputStreamReader classes, which are used for File I/O. These are predefined classes in Android, and that’s why we first create an object of that class. From documentation:
“An OutputStreamWriter is a bridge from character streams to byte streams: Characters written to it are encoded into bytes using a specified charset. The charset that it uses may be specified by name or maybe given explicitly, or the platform’s default charset may be accepted.
Each invocation of a write() method causes the encoding converter to be invoked on the given character(s). The resulting bytes are accumulated in a buffer before being written to the underlying output stream. The size of this buffer may be specified, but by default, it is large enough for most purposes. Note that the characters passed to the write() methods are not buffered.”
“An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. The charset that it uses may be specified by name or maybe given explicitly, or the platform’s default charset may be accepted.
Each invocation of one of an InputStreamReader’s read() methods may cause one or more bytes to be read from the underlying byte-input stream. To enable the efficient conversion of bytes to characters, more bytes may be read ahead from the underlying stream than are necessary to satisfy the current read operation.”
Link: https://developer.android.com/reference/java/io/InputStreamReader
- These are the classes used to read from and write to files. To read from files, we use the BufferedReader class to read from files easily, without getting conversion issues.
- The write() method of OutputStreamWriter is used to write to files.
- The readLine() method of BufferedReader is used to read a line of text from the file.
- It is very important to close the Input or Output stream after I/O operations. Hence, the close() button is used to do that.
Implementing the save functionality
Now we’ll implement the saving of text written in the EditText, by clicking the save button.
We’ll also add a Toast message to let the user know that their text has been saved.
A Toast is a small popup that appears at the bottom of the screen for a short duration. Write the following in the onCreate() function in MainActivity.java:
setOnClickListener() is used to set up click events. Here, we have used it to call the method for saving the text into the file, whenever the button is clicked.
We need to read from the file as well, whenever the app opens. Write the following in the onCreate() function of MainActivity.java:
The coding part ends here. Now let us test our app.
Testing the Scratchpad App
Let’s now move forward and run the app. Hit the run icon (Green Play button on top). The app will build, and you should see the following: Final Look of the App
Type in some text, and hit the save button.
Hit the back button to close the app. After Typing Text and Hitting the Save Button
Now, reopen the app (Find the app icon in the app menu on the phone). After Reopening the App
Voila! It’s still there.
We have built a fully functional scratchpad app. Go ahead and use it to jot down some notes!
How to view the contents of a private .txt file in Android?
Since we have created the file in Private mode, it cannot be accessed directly. It will not be visible to any other application other than this App. However, if we want to view the contents of this file, we can do that in the command line. The steps are as follows:
- Run the emulator. This is very important since the commands won’t run without a running emulator instance.
- Navigate to the [android-sdk]/platform-tools folder and run the following commands (Replace your-package-name with the package name of your app, it is the first line in MainActivity.java file):
You should now see the contents of the file in your command line window. Viewing the Contents of the File using Command Line
Complete Code for the Scratchpad App
activity_main.xml
colors.xml
Java File
Don’t forget to replace the package name with your package name if you are going to copy this entire code!
Android Studio auto-generates most of the code in the beginning. So, you only need to add the additional code. No need to change the already present code.
About the author
Undergraduate student pursuing B.Tech in Information Technology from MSIT, Delhi. An aspiring Android Developer who loves to stay up to date about the latest trends in technology.
Back to course page
Share and Support
Leave a Reply Cancel reply
This site uses Akismet to reduce spam. Learn how your comment data is processed.
Источник