android - 带有 getView() 的 ListView 由于不断的 GC 而过度缓慢?

标签 android performance listview garbage-collection lag

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

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

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

所以我的问题是,什么可能导致每隔 200 毫秒左右持续进行一次垃圾收集,我该如何预防?它确实减慢了我的应用程序速度,我担心如果我不解决它会让一些用户望而却步。

谢谢, 亚历克斯。

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,它现在立即打开 - 万岁!

第二次更新:

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

最佳答案

一般来说,垃圾回收的发生是因为您不必要地创建了太多对象。帮助您编写代码会更容易,但我还是会试一试。

对于您的列表,您可能会在每次调用 getView 时重新创建 View 。您应该在适当的时候重新使用 convertView。看我的answer关于如何构造您的 getView 方法的其他 SO 问题。

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

更新:

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

关于android - 带有 getView() 的 ListView 由于不断的 GC 而过度缓慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7166427/

相关文章:

java - 计算工作时间和现金

android - SQLiteDatabase.openDatabase 与 SQLiteOpenHelper.getReadableDatabase

python - Python 中的快速组合生成器

android - 我的列表、 ScrollView 和按钮出错

android - 对于 ListView 适配器,如何调用 getView()?

android - 在 TAB 中显示 ListViews 的问题

android - git push 后终端卡住了

javascript - 已弃用的 domLoading 已删除!用什么代替?

python - 使用 Numpy 高效地按行排列数组

android - 本 map 片通过android中的本地json