问题
I'm working on a gallery app which displays all the images in a phone or a pen-drive. I successfully managed to list all the images and displays it into the app. But I think it is pretty slow. I'm using Depth First Search technique inside an AsyncTask. So is there any other method which can be used inside AsyncTask which is much faster.
Here root is a DocumentFile which is made from a tree URI.
Here is the code I've used.
public class ImageBackgroundTask extends AsyncTask<Object, Object, ArrayList<DocumentFile>> {
DocumentFile root;
ArrayList<DocumentFile> result;
ProgressDialog pg;
Context context;
private AsyncTaskCompleteListener<ArrayList<DocumentFile> > callback;
ImageBackgroundTask(DocumentFile root, Context context, AsyncTaskCompleteListener<ArrayList<DocumentFile>> cb){
this.context=context;
this.root=root;
this.callback = cb;
}
@Override
protected ArrayList<DocumentFile> doInBackground(Object... voids) {
Queue<DocumentFile> stack=new ArrayDeque<>();
ArrayList<DocumentFile> list=new ArrayList<>();
for(DocumentFile f:root.listFiles()){
stack.add(f);
}
while(!stack.isEmpty()){
DocumentFile child=stack.remove();
if(child.isDirectory()){
for(DocumentFile file:child.listFiles()){
stack.add(file);
}
}
else if(child.isFile()){
String name=child.getName();
if(name.endsWith(".jpg")
|| name.endsWith(".png")
|| name.endsWith("jpeg")
|| name.endsWith("JPG")
|| name.endsWith("JPEG")
|| name.endsWith("PNG"))
list.add(child);
}
}
return list;
}
@Override
protected void onPreExecute() {
pg=new ProgressDialog(context);
pg.setMessage("Loading...");
pg.show();
}
@Override
protected void onProgressUpdate(Object... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(ArrayList<DocumentFile> aVoid) {
pg.dismiss();
result=aVoid;
callback.onTaskComplete(result);
}
Here is the output.
Checkout the GIF
回答1:
Do not use DocumentFile.listFiles() to list the files for a tree uri you obtained with Intent.ACTION_OPEN_DOCUMENT_TREE.
As it is notoriously slow.
Instead use functions from DocumentsContract.
Look at the void traverseDirectoryEntries(Uri rootUri) function from Issues traversing through directory hierarchy with Android Storage Access Framework / DocumentProvider using MTP
Collect the child uri for every file instead of trying to obtain a DocumentFile for it.
Then later you can use that child uri to load the image.
If you need six seconds now then it will be less than a second with DocumentsContract i think.
回答2:
This is how I usually do these kinds of things:
public ArrayList<String> getFile(File directory) {
File listFile[] = directory.listFiles();
if (listFile != null && listFile.length > 0) {
for (File file : listFile) {
if (file.isDirectory()) {
getFile(file);
}
else {
if (file.getName().endsWith(".png")
|| file.getName().endsWith(".jpg"))
{
String temp = file.getPath().substring(0, file.getPath().lastIndexOf('/'));
if (!fileList.contains(temp))
fileList.add(temp);
}
}
}
}
return fileList;
}
来源:https://stackoverflow.com/questions/47366768/how-to-list-all-files-inside-a-directory-including-sub-directories-efficiently