ListView与getView()由于常量GC而过度缓慢?

时间:2011-08-23 19:25:46

标签: android performance listview garbage-collection lag

我的应用程序中有一个ListView,并且我已经覆盖了getView()方法,因此我可以根据行的文本更改行的ImageView src。

问题是,我注意到ListView滚动滞后,当我检查DDMS时,似乎每次滚动ListView时都会调用垃圾收集器,从而减慢滚动速度。

我还注意到在我的应用程序的不同部分调用垃圾收集器时,从BufferedReader读取行,这使得打开一个2,000行文件需要大约47秒,其中作为文件exporer我安装在我的手机会在大约2秒内打开同一个文件。

所以我的问题是,每200ms左右可能导致不断的垃圾收集,我该如何预防呢?这真的会减慢我的应用程序速度,我担心如果我不解决它会让一些用户关闭。

谢谢, 亚历克斯。

ListView getView():

class IconicAdapter extends ArrayAdapter<String> {
  IconicAdapter(){
    super(FileBrowser.this, R.layout.filebrowser_listview_row, R.id.listtext, directoryEntries);
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent){
    View row = super.getView(position, convertView, parent);
    TextView text = (TextView) row.findViewById(R.id.listtext);
    ImageView icon = (ImageView) row.findViewById(R.id.listicon);

    entryFullFileName = directoryEntries.get(position).toString();

    if(entryFullFileName.contains(".") && !entryFullFileName.matches("^\\.+$")){
      String[] parts = entryFullFileName.split("\\.");
      lastIndex = parts.length - 1;
      fileType = parts[lastIndex];
    }else{
      fileType = "";
    }

     if(fileIsDir.get(position) == true){
      icon.setImageResource(R.drawable.folderlightblue);
     }else if(fileType.equals("html")){
      icon.setImageResource(R.drawable.filehtml);
     }else if(fileType.equals("css")){
      icon.setImageResource(R.drawable.filecss);
     }else if(fileType.equals("js")){
      icon.setImageResource(R.drawable.filejs);
     }else if(fileIsDir.get(position) == false){
      icon.setImageResource(R.drawable.fileplain);
     }

   return(row);
  }
}  

代码打开文件

我前几天删除了代码,记录了打开文件花了多少秒,但是花了47秒而且花了太长时间,而while循环正在做这件事,那就是持续的调用到垃圾收集器,我猜测文件读取速度慢的原因 - 是的,这个函数是在一个线程中调用的,当读取文件时显示progressDialog

private String getLocalFileContents(String fileUri){
  try{
    String contents = "";
    BufferedReader in = new BufferedReader(new FileReader(fileUri));
    String line;
    while((line = in.readLine()) != null){
      contents += line + "\n";
    }
    in.close();

    return contents;
  }catch(Exception e){
    toast.setText("Failed to open sdcard file, try again.");
  }
 return null;
}

更新

解决了文件读取问题,结果是字符串连接使垃圾收集器在每次循环后被调用,大大减慢了文件读取速度。正如答案所建议的那样,我使用的是StringBuilder,它现在又开启了第二个 - 万岁!

2ND UPDATE:

我知道滚动ListView时常量GC调用的原因是什么,它是ListView属性android:cacheColorHint =“@ android:color / transparent” - 但我不知道解决方法!

4 个答案:

答案 0 :(得分:1)

通常,垃圾收集正在发生,因为您不必要地创建了太多对象。帮助你的代码会更容易,但无论如何我都会试一试。

对于您的列表,您可能会在每次调用getView时重新创建您的视图。相反,您应该在适当时重复使用convertView。有关如何构建getView方法的建议,请参阅我的answer至其他SO问题。

你的文件阅读问题有点难以猜测,但是对于2,000行来说,47s似乎非常长。你是否也在该循环中创建对象?

<强>更新

显然,你的问题与你自己的View对象无关,但这是你每次获得View时所做的所有工作。你每次都做了很多工作:一个RegEx匹配,字符串拆分(和相关的字符串对象创建)等。你应该至少缓存这个结果,这样你就不必为每个工作重做工作了。项目每次回到视图中。

答案 1 :(得分:1)

一种优化方法是停止拆分整个字符串以获取文件类型。你可以使用像

这样的东西
String fileType = "";
int lastDot = entryFullFileName.lastIndexOf(".");
if(lastDot!=-1) {
    fileType = entryFullFileName.substring()
}

但这当然不应该花费47秒。

答案 2 :(得分:0)

在这里查看EfficientAdapter是link

并在其他线程中详细解释了有效的适配器和getView方法,看看它是link

希望这有帮助!!!

答案 3 :(得分:0)

是的,android:cacheColorHint =“@ android:color / transparent”导致在某些操作系统版本上过度调用垃圾收集器(不确定最新版本是否已修复)。

好吧,试着不要用它。例如,我与我的设计师交谈,向他们解释了滞后原因的问题,他们同意不使用透明背景。