I've made a CustomListAdapater which works fine, however, I get quite a few garbage collection messages popping up when I scroll through the list quickly.
Is there a best practice to making a efficient custom ListAdapter?
Here's what I have t the moment what works, but isn't great.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
RelativeLayout centreView;
//Get the current alert object
if (convertView == null) {
centreView = new RelativeLayout(getContext());
LayoutInflater vi;
vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi.inflate(resource, centreView, true);
}
else
{
centreView = (RelativeLayout) convertView;
}
TextView name = (TextView) centreView.findViewById(R.id.class_name);
TextView venue = (TextView) centreView.findViewById(R.id.class_venue);
TextView time = (TextView) centreView.findViewById(R.id.class_time);
TextView room = (TextView) centreView.findViewById(R.id.class_room);
TextView id = (TextView) centreView.findViewById(R.id.class_id);
TextView dayTV = (TextView) centreView.findViewById(R.id.class_day);
TextView desc = (TextView) centreView.findViewById(R.id.class_description);
TextView json = (TextView) centreView.findViewById(R.id.class_json);
String timeString;
try {
JSONObject thisRow = items.get(position);
name.setText(thisRow.getString("className"));
dayTV.setText(thisRow.getString("theDate"));
json.setText(thisRow.toString());
venue.setText(thisRow.getString("venue"));
final String ID = thisRow.getString("id");
id.setText(ID);
desc.setText(thisRow.getString("description"));
timeString = thisRow.getString("startTime");
timeString += " - "+thisRow.getString("endTime");
time.setText(timeString);
room.setText(thisRow.getString("room"));
final Button alter = (Button) centreView.findViewById(R.id.is_alt);
alter.setVisibility(View.INVISIBLE);
final JSONArray alterations = thisRow.getJSONArray("alteration");
if (alterations.getJSONObject(0).getString("show").equals("yes")) {
alter.setVisibility(View.VISIBLE);
alter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ActivityViewTimetable actVT = (ActivityViewTimetable) getContext();
actVT.showAlterations(alterations);
}
});
}
} catch (JSONException e) {
Log.e("FUApp", "JSON Error (TimetableItemsArrayAdapter): " + e.getMessage());
}
return centreView;
}
PS. Some of the TextView i'm referencing arn't needed anymore, I'm just sorting out which ones at the moment.
EDIT: This is what I've ended up with
static class ViewHolder {
TextView name;
TextView venue;
TextView time;
TextView room;
TextView id;
TextView dayTV;
TextView desc;
TextView json;
JSONObject jsonObj;
String classNameString;
String theDate;
String venueString;
String idString;
String description;
String startTime;
String endTime;
String roomString;
JSONArray alterations;
}
and
if (convertView == null) {
centreView = new RelativeLayout(getContext());
LayoutInflater vi;
vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi.inflate(resource, centreView, true);
holder = new ViewHolder();
holder.name = (TextView) centreView.findViewById(R.id.class_name);
holder.venue = (TextView) centreView.findViewById(R.id.class_venue);
holder.time = (TextView) centreView.findViewById(R.id.class_time);
holder.room = (TextView) centreView.findViewById(R.id.class_room);
holder.id = (TextView) centreView.findViewById(R.id.class_id);
holder.dayTV = (TextView) centreView.findViewById(R.id.class_day);
holder.desc = (TextView) centreView.findViewById(R.id.class_description);
holder.json = (TextView) centreView.findViewById(R.id.class_json);
holder.jsonObj = items.get(position);
try {
holder.classNameString = holder.jsonObj.getString("className");
holder.theDate = holder.jsonObj.getString("theDate");
holder.venueString = holder.jsonObj.getString("venue");
holder.idString = holder.jsonObj.getString("id");
holder.description = holder.jsonObj.getString("description");
holder.startTime = holder.jsonObj.getString("startTime");
holder.endTime = holder.jsonObj.getString("endTime");
holder.roomString = holder.jsonObj.getString("room");
holder.alterations = holder.jsonObj.getJSONArray("alteration");
}
catch (JSONException e) {
Log.e("FUApp", "JSONError getting details: "+e.getMessage());
}
centreView.setTag(holder);
}
Using this my list doesn't lag at all.
Use a View Holder
Your code might call findViewById()
frequently during the scrolling of ListView, which can slow down performance. Even when the Adapter returns an inflated view for recycling, you still need to look up the elements and update them. A way around repeated use of findViewById()
is to use the "view holder" design pattern.
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
You can initialize Layout Infalter in the constructor of your Adapter class
Edit:
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.mylayouttoinflate, null);
// initialize views like holder.text = (TextView)convertView.findViewByID(R.id.text);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// set text to text view
holder.text.setText("hi");
return convertView;