Search code examples
androidscoped-storagedocumentfile

Android 11: DocumentFile findFile() is too slow


With this update of Google's storage policy, I had to change the way I save files.

First, my application previously saved the project folder to /sdcard/. However, due to this policy, access using File became impossible, and I tried several methods.

I also thought about saving it in an App-specific files space, but since the project folder should not be deleted when deleting the app, it cannot be used.

1. Using MediaStore

At first, I tried using MediaStore. I was able to put files in a folder by using RELATIVE_PATH, but the control of the files was very difficult, and the files in the project folder are also files that are not related to media (photos, videos, music).

2. Using DocumentFile

I found another way. Using Intent's ACTION_OPEN_DOCUMENT_TREE, I got access rights and tree uri of the project folder from the user, and I was able to access the file by creating a DocumentFile with it.

At first I thought this was a very good way to do it, but soon I found it to be slow.

In particular, for the findFile() method, it takes nearly a second to scan a single file. There are dozens of files in my project folder, so this couldn't be commercialized.

Is there a better way? There have been some posts asking you to try out DocumentContracts, but it seems that there is no function to get a list of files or check their existence.

Below is my current code: First, request tree uri:

public void getTreeUri(View view) {
    Intent i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    startActivityForResult(i, 200);
}

Second, get tree uri:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode==200 && resultCode == Activity.RESULT_OK) {
        final int takeFlags = data.getFlags()  & (Intent.FLAG_GRANT_READ_URI_PERMISSION  | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        getContentResolver().takePersistableUriPermission(data.getData(), takeFlags);

        Log.d("test", "Tree Uri: " + data.getDataString());

        treeUri = data.getDataString();
        getFileList();
    }
}

And, in particular, it gets very slow when findFile is used like this.

public void getFileList(){
    DocumentFile df = DocumentFile.fromTreeUri(this, Uri.parse(treeUri));
    DocumentFile[] df_list = df.listFiles();
    for (DocumentFile each : df_list){
        Log.d("test","File: "+ df.findFile(each.getName()));  //findFile method is too SLOW!
    }
}

Solution

  • For Android 10 you can request legacy external storage in manifest and you can continue in the old way using File class and so.

    For Android 11 use your own directory in one of the public dirs like Download, Documents, Pictures, Alarms and so on. No need for saf also.