Reputation: 2027
I have a ListView in my app, and I've over-ridden the getView() method so I can change the row's ImageView src depending on the row's text.
The problem is, I've noticed the ListView scrolling is lagging, and when I check DDMS, it seems the Garbage Collector is being called everytime the ListView is being scrolled, thus slowing the scrolling.
I've also noticed the Garbage Collector being called in a different part of my app, when reading lines from a BufferedReader, which makes opening a 2,000 line file take ~47 seconds, where as a file exporer I have installed on my phone opens that same file in about 2 seconds.
So my question is, what could be causing the constant Garbage Collection every 200ms or so, and how do I prevent it? It's really slowing my app down and I fear it will put some users off if I don't solve it.
Thanks, Alex.
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);
}
}
Code To Open File
I removed the code the other day that logged how many seconds it took to open the file, but it took 47 seconds and definitely took too long, and again while the while loop is doing it's thing, there's constant calls to the Garbage Collector, which I'm guessing in the cause of the slow file reading - and yes, this function is called in a thread with progressDialog showing while the file is being read
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;
}
UPDATE:
The file reading problem is solved, turns out the String concatenation made the Garbage Collector get called after each loop, dramatically slowing the file reading down. As suggested by an answer I used StringBuilder instead and it now opens in a second - hooray!
2ND UPDATE:
I know what the cause of the constant GC calls when scrolling my ListView is, it's the ListView attribute android:cacheColorHint="@android:color/transparent" - but I don't know a work-around!
Upvotes: 3
Views: 1552
Reputation: 10583
Yes, android:cacheColorHint="@android:color/transparent" is causing excessive calling of the garbage collector on some OS versions (not sure if the newest ones this is fixed).
Well, just try to not use it. For example, I spoke with my designers, explained them the problem about the cause of the lags, and they agreed to not use the transparent background.
Upvotes: 0
Reputation: 751
One optimization would be to stop splitting the entire string to get the filetype. You could use something like
String fileType = "";
int lastDot = entryFullFileName.lastIndexOf(".");
if(lastDot!=-1) {
fileType = entryFullFileName.substring()
}
That certainly shouldn't take 47s though.
Upvotes: 1
Reputation: 1719
Look at EfficientAdapter here is link
And explained more about efficient adapter and getView method in other thread have a look at it, here is link
Hope this help!!!
Upvotes: 0
Reputation: 36302
In general, garbage collection is happening because you're creating too many objects unnecessarily. It'd be easier to help with your code, but I'll give it a shot anyway.
In the case of your list, you're probably recreating your view in every call to getView
. You should instead re-use convertView
when appropriate. See my answer to this other SO question for an idea of how to structure your getView
method.
Your file reading problem is a bit harder to guess at, but 47s seems ridiculously long for 2,000 lines. Are you also creating objects in that loop?
Update:
So apparently your problem isn't really with your View
objects themselves, but it's all the work you do every time you get a View
. You're doing quite a bit of work every time: a RegEx match, string splitting (and associated string object creation), etc. You should at minimum cache the results of this so that you don't have to redo the work for each item every time it comes back into view.
Upvotes: 1