2013-05-16 158 views
3

在我的Android应用程序中,我将外部存储的所有路径填充到数组中。java.lang.StackOverflowError递归目录

少数设备正在报告StackOverflowError

我读过many linked posts关于这个问题的原因,但我不知道如何处理它或防止它在我使用的代码内发生。我也不理解Android可以处理的'递归限制'。

以下代码适用于from this source

private final Locale loc = SupportedLanguages.isSupported(); 
private final String CACHE = "cache"; 
private final String TEMP = "temp"; 

@Override 
protected Boolean doInBackground(Void... params) { 

     final File fileList = Environment.getExternalStorageDirectory(); 

     final String absolutePath = Environment.getExternalStorageDirectory().getAbsolutePath(); 

     final File[] dirList = fileList.listFiles(); 

     final List<File> listDirs = Arrays.asList(dirList); 

     if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 

      final ArrayList<String> dirPath = new ArrayList<String>(); 
      final ArrayList<String> dirName = new ArrayList<String>(); 
      String fileName = ""; 

      for (final File startingDirectory : listDirs) { 
       if (!startingDirectory.isFile() && startingDirectory.canRead() && !startingDirectory.isHidden()) { 

        final List<File> files = getFileListing(startingDirectory); 

        if (files != null) { 

         for (final File file : files) { 

          fileName = file.getPath().replaceAll(absolutePath, "").toLowerCase(loc).replaceAll("\\/", " ") 
            .trim(); 
          fileName = fileName.replaceAll(" +", " "); 

          dirName.add(fileName); 
          dirPath.add(file.toString()); 
         } 
        } 
       } 
      } 

     } 


    return true; 
} 

private List<File> getFileListing(File aStartingDir) { 
    List<File> result = getFileListingNoSort(aStartingDir); 

    if (result != null && !result.isEmpty()) { 
     Collections.sort(result); 
    } 
    return result; 
} 

private List<File> getFileListingNoSort(File aStartingDir) { 
    List<File> resultArray = new ArrayList<File>(); 
    File[] filesAndDirs = aStartingDir.listFiles(); 

    if (filesAndDirs != null && filesAndDirs.length > 0) { 

     List<File> filesDirs = Arrays.asList(filesAndDirs); 

     for (File file : filesDirs) { 
      if (!file.isFile() && file.canRead() && !file.isHidden() && !file.getName().toLowerCase(loc).startsWith(CACHE) 
        && !file.getName().toLowerCase(loc).startsWith(TEMP)) { 

       resultArray.add(file); 
       List<File> deeperList = getFileListingNoSort(file); 
       resultArray.addAll(deeperList); 
      } 
     } 
    } 

    return resultArray; 
} 

崩溃日志:

> Caused by: java.lang.StackOverflowError at 
> java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:145) 
> at java.lang.StringBuilder.append(StringBuilder.java:216) at 
> java.io.File.join(File.java:215) at java.io.File.<init>(File.java:157) 
> at java.io.File.<init>(File.java:124) at 
> java.io.File.filenamesToFiles(File.java:852) at 
> java.io.File.listFiles(File.java:791) at 
> com.mypackage.name.ll.a(Unknown Source) at 
> com.mypackage.name.ll.a(Unknown Source) at 
> com.mypackage.name.ll.a(Unknown Source) at 
> com.mypackage.name.ll.a(Unknown Source) at 
> com.mypackage.name.ll.a(Unknown Source) at 
> com.mypackage.name.ll.a(Unknown Source) at 
> com.mypackage.name.ll.a(Unknown Source) at 
> com.mypackage.name.ll.a(Unknown Source) at 
> com.mypackage.name.ll.a(Unknown Source) 

等等......

ProGuard的映射:

com.mypackage.name.GenerateSubDirectoryList -> com.mypackage.name.ll: 
java.util.List getFileListingNoSort(java.io.File) -> a 

某处,我需要算递归并应用一个限制。但我不知道适用于Android或个别设备硬件的位置或限制?

在此先感谢您的帮助。

回答

1

计数递归很简单:只需添加一个int参数的getFileListingNoSort方法,并增加在每次调用值:

private List<File> getFileListingNoSort(File aStartingDir, int level) { 
    List<File> resultArray = new ArrayList<File>(); 
    File[] filesAndDirs = aStartingDir.listFiles(); 

    if (level < MAX_LEVEL && filesAndDirs != null && filesAndDirs.length > 0) { 

     List<File> filesDirs = Arrays.asList(filesAndDirs); 

     for (File file : filesDirs) { 
      if (!file.isFile() && file.canRead() && !file.isHidden() && !file.getName().toLowerCase(loc).startsWith(CACHE) 
        && !file.getName().toLowerCase(loc).startsWith(TEMP)) { 

       resultArray.add(file); 
       List<File> deeperList = getFileListingNoSort(file, ++level); 
       resultArray.addAll(deeperList); 
      } 
     } 
    } 

    return resultArray; 
} 

但问题仍然是:这将是对MAX_LEVEL和为什么最好的价值它是无限循环的。有问题的文件系统可能具有创建周期的符号链接。

+0

谢谢安德烈亚斯。是的,问题仍然是这个限制应该设置为什么?另外,我看过帖子中超过了'最大整数级别',应该使用长整型。不知道这个限制,我不知道这是否也需要考虑?可能不太可能是由于计数是存储路径。感谢您指出符号链接 - 我不认为这一点。我会调查。 – brandall

1

Android运行在很多硬件上,其中很多硬件根本没有多少堆栈;而不是通过递归子目录,做一个广度优先搜索,即:

private List<File> getFileListingNoSort(File aStartingDir) 
{ 
    // assuming aStartingDir is a valid input 
    List<File> dirsToSearch = new ArrayList<File>(); 
    dirsToSearch.add(aStartingDir); 
    List<File> resultArray = new ArrayList<File>(); 
    do{ 
     File thisDir = dirsToSearch.remove(0);  
     List<File> filesDirs = Arrays.asList(thisDir.listFiles()); 

     for (File file : filesDirs) 
     { 
      if (file.isDirectory()) 
      { 
       dirsToSearch.add(file); 
      } 
      else if(file.canRead() && 
         !file.isHidden() &&  
         !file.getName().toLowerCase(loc).startsWith(CACHE) && 
         !file.getName().toLowerCase(loc).startsWith(TEMP)) 
      { 
       resultArray.add(file);    
      } 
     } 
    } while(false == dirsToSearch.isEmpty()); 
    return resultArray; 
} 

买者自负:我没有运行,甚至看看这个代码编译。

但这个想法是,维护一个目录列表,从您关心的目录开始,从该列表中删除第一个目录,将该目录中的文件添加到结果中(修改代码以将目录添加到resultArray如果你想要的目录),将目录添加到要搜索的目录列表,并继续,直到目录列表为空。

递归是坏的,如果你不能提前知道你需要递减多少,或者你有多远。我不认为文件系统迭代是递归的适当位置,但这是我个人的看法。

+0

谢谢本,但我有点困惑 - '维护目录列表'< - 我怎么能做到这一点,而不递归创建一个!? – brandall

+0

当在遍历filesDirs的过程中遇到目录时,将其添加到dirsToSearch;否则,您检查它是否符合您的条件,如果符合,则将其添加到resultsArray中。只要有已添加但未列出的目录,do ... while循环将继续,列出目录的第一步是将其从dirsToSearch中移除。 –

+0

我需要一点时间来消化你的建议实现。感谢您回复澄清。 – brandall