2

As Google is trying to enforcing apps to use SAF for storage access, I am trying to adapt my app to use SAF replacing java file io apis.

I have spent many hours study the SAF APIs (mainly DocumentFile and DocumentContract classes) but still have some difficulties.

First one is how to move a file to another directory? DocumentFile does have a method to rename a file, but it is just the display name of the file. How can I move a file to another folder, if it is a huge file which I don't want to copy it. Assume src and dst are on the same partition.

Second question is how to list child files efficiently. I checked the source code and found that DocumentFile.listFiles() impl only queries the child files with single projection [ID]. And later when I want to display the files in a list view with their names, the call to DocumentFile.getName() will trigger another query via content resolver for each file again. This is a huge impact on the performance of the code. Especially when I try to sort an array of DocumentFile by their names, 30+ files will cost 600+ms, which is far beyond the acceptable. I doubt whether I am using the correct API set. Could anyone point out a better way to list files with names (and other properties)?

Robin
  • 10,052
  • 6
  • 31
  • 52
  • Use DocumentsContract to list files and directories. Query the content resolver with the obtained uri. It's 20 times faster. – blackapps Nov 20 '19 at 10:22
  • 2
    @blackapps DocumentsContract.moveDocument is available from API 24. Is there a way to support API 21? – artman Nov 20 '19 at 12:14
  • 1
    Dont think so. Never used moveDocument. Experimenting now. How do you determine the value for the second parameter (the parent dir) if you have only an uri for the source file? – blackapps Nov 20 '19 at 12:49
  • To answer my own question, you can't. And if you could you would not have read or write rights for that parent directory to move a file from it. (Assuming that you only once picked a source file and a destination directory). Just my thougths. – blackapps Nov 20 '19 at 18:34
  • DocumentsContract.moveDocument() can move a file or a directory i now tested. Both. But.. on the same partition. – blackapps Nov 20 '19 at 18:36
  • 2
    To support API 21: https://github.com/commonsguy/cwac-document – blackapps Nov 20 '19 at 20:21
  • https://stackoverflow.com/questions/47366768/how-to-list-all-files-inside-a-directory-including-sub-directories-efficiently – blackapps Nov 21 '19 at 15:25

1 Answers1

2

Simple Storage is a library that simplify SAF across API levels. Suppose that you want to move a MP4 file from directory Video in external storage into directory Others in SD card. Let's assume that AAAA-BBBB as SD card's storage ID:

val source = DocumentFileCompat.fromSimplePath(context, basePath = "Video/Infinity War.mp4")
val targetFolder = DocumentFileCompat.fromSimplePath(context, storageId = "AAAA-BBBB", basePath = "Others")

// To move file:
source.moveFileTo(context, targetFolder, callback)

// To copy file:
source.copyFileTo(context, targetFolder, callback)
Anggrayudi H
  • 14,977
  • 11
  • 54
  • 87