我的应用程序中有一个 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/