The question is specifically for apps targeting API 31 and above.
I have referred to a lot of similar StackOverflow questions, Official Docs, etc.
There are some limitations to API 31 as mentioned here - Docs.
Usecase
To write a JSON file to the device's external storage so that the data is not lost even if the app is uninstalled.
How to achieve this for apps, targeting API 31 and above?
My current code saves the file to app-specific storage directory obtained using context.getExternalFilesDir(null)
.
The problem is that the file is not retained when the app is uninstalled.
Any blogs or codelabs explaining the exact scenario are also fine.
Note
- Aware that the user can see, modify or delete the file from other apps when we store it in the external storage directory - That is fine.
- Device root directory, Documents, or any other location is fine, given that all devices can access the file in the same way.
CodePudding user response:
Your app can store as much files in public Documents or Download directory and sub directories as it wants without any user interaction. All with classic file means.
At reinstall you use ACTION_OPEN_DOCUMENT_TREE to let the user choose the used subfolder.
CodePudding user response:
First you ask is there a way to skip user manual selection, the answer is yes and no, it's yes if you get MANAGE_EXTERNAL_STORAGE permission from the user but as it is a sensitive and important permission google will reject your app to be published on google play if it is not a file-manager or antivirus or other app that really needs this permission. read this page for more info and the answer is no if you don't use MANAGE_EXTERNAL_STORAGE permission.
You should use Storage Access Framework, It doesn't need any permission, I will tell you how to implement it:
Imagine you have saved JSON to a text file, here is the steps to restore data from it:
1- We need a method that displays a dialog to the user, so he/she can choose saved file:
private void openFile() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("text/*");
someActivityResultLauncher.launch(intent);
}
2- We should implement onActivityResult to get the uri of the file that user has selected, so add someActivityResultLauncher to activity class:
ActivityResultLauncher<Intent> someActivityResultLauncher;
3- Add following methods to Activity class:
private void registerActivityResult()
{
someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
Uri uri = data.getData();
// Perform operations on the document using its URI.
try {
String txt = readTextFromUri(Setting_Activity.this, uri);
dorestore(txt);
}catch (Exception e){}
}
}
});
}
4- Call the above method in onCreate() method of activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
//......
registerActivityResult();
//.....
}
5- Implement the readTextFromUri() method we used in step 3:
public static String readTextFromUri(Context context, Uri uri) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
try (InputStream inputStream =
context.getContentResolver().openInputStream(uri);
BufferedReader reader = new BufferedReader(
new InputStreamReader(Objects.requireNonNull(inputStream)))) {
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
}
return stringBuilder.toString();
}
That's all, just implement the dorestore() method we used in step 3 to restore your json data. in mycase it looke something like this:
private void dorestore(String data)
{
ArrayList<dbObject_user> messages = new ArrayList<>();
try {
JSONArray jsonArray = new JSONArray(data);
//....
//parsing json and saving it to app db....
//....
}
catch (Exception e)
{}
}
just call the openFile() in step 1. That's all.