3

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

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

我还注意到垃圾收集器在我的应用程序的不同部分被调用,当从 BufferedReader 读取行时,这使得打开一个 2,000 行文件需要大约 47 秒,而我在手机上安装的文件导出器打开了在大约 2 秒内完成相同的文件。

所以我的问题是,什么可能导致每隔 200 毫秒左右进行一次持续的垃圾收集,我该如何防止呢?这真的让我的应用程序变慢了,我担心如果我不解决它会让一些用户失望。

谢谢,亚历克斯。

列表视图 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 ,现在它会在一秒钟内打开 - 万岁!

第二次更新:

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

4

4 回答 4

1

一种优化是停止拆分整个字符串以获取文件类型。你可以使用类似的东西

String fileType = "";
int lastDot = entryFullFileName.lastIndexOf(".");
if(lastDot!=-1) {
    fileType = entryFullFileName.substring()
}

不过,这当然不应该花费 47 秒。

于 2011-08-23T19:50:12.007 回答
1

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

对于您的列表,您可能在每次调用getView. 您应该convertView在适当的时候重新使用。请参阅我对其他 SO 问题的回答,了解如何构建您的getView方法。

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

更新:

因此,显然您的问题并不在于您的View对象本身,而是您每次获得View. 您每次都在做很多工作:RegEx 匹配、字符串拆分(以及关联的字符串对象创建)等。您至少应该缓存此结果,这样您就不必为每个都重做工作项目每次重新出现时。

于 2011-08-23T19:36:21.057 回答
0

看看这里的 EfficientAdapter 是链接

并在其他线程中解释了有关高效适配器和 getView 方法的更多信息,请看一下,这里是链接

希望这有帮助!!!

于 2011-08-23T19:50:08.793 回答
0

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

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

于 2013-01-11T09:17:50.297 回答