benkdev benkdev - 4 months ago 14
Android Question

ListView is very laggy - Android

I've created a custom ListView. I've tried to optimize the getView method of my ListView's Adapter but I'm still experiencing lag.

What am I doing wrong in the Adapter that causes my ListView to lag?

Or if it looks good, what could be causing the lag?

The xml of a row in the ListView is:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="6dip"
android:background="@color/all_white"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="6dip"
android:background="@color/all_white"
android:gravity="center">
<TextView
android:layout_width="40dip"
android:layout_height="wrap_content"
android:paddingTop="10dip"
android:paddingBottom="10dip"
/>
<Button
android:layout_width="197dip"
android:layout_height="wrap_content"
android:layout_marginRight="8dip"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:background="@drawable/button_300"
android:textColor="@color/all_white"
/>
<Button
android:layout_width="197dip"
android:layout_height="wrap_content"
android:layout_marginRight="8dip"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:background="@drawable/button_300"
android:textColor="@color/all_white"
/>
<Button
android:layout_width="197dip"
android:layout_height="wrap_content"
android:layout_marginRight="8dip"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:background="@drawable/button_300"
android:textColor="@color/all_white"
/>
<Button
android:layout_width="197dip"
android:layout_height="wrap_content"
android:layout_marginRight="8dip"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:background="@drawable/button_300"
android:textColor="@color/all_white"
/>
<Button
android:layout_width="197dip"
android:layout_height="wrap_content"
android:layout_marginRight="8dip"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:background="@drawable/button_300"
android:textColor="@color/all_white"
/>
<Button
android:layout_width="197dip"
android:layout_height="wrap_content"
android:layout_marginRight="8dip"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:background="@drawable/button_300"
android:textColor="@color/all_white"
/>
</LinearLayout>
</LinearLayout>


The code for my Adapter is:

public class MultiWorkspaceAdapter2 extends BaseAdapter {

/*
* A map of the workspaces of a user, with key == first letter of the workspace title
* and value == the list of WorkspaceInfos for that key.
*/
private LinkedHashMap<String, List<WorkspaceInfo>> _workspacesMap;

/*
* Array of keys in order to get the values in getItem.
*/
private String[] _keys;

private Activity _activity;

public MultiWorkspaceAdapter2(Activity activity, LinkedHashMap<String, List<WorkspaceInfo>> map) {
_workspacesMap = map;
_keys = (String[]) _workspacesMap.keySet().toArray(new String[_workspacesMap.size()]);
_activity = activity;
}

public int getCount() {
return _workspacesMap.size();
}

public Object getItem(int position) {
_keys = (String[]) _workspacesMap.keySet().toArray(new String[_workspacesMap.size()]);
List<WorkspaceInfo> list = new ArrayList<WorkspaceInfo>();
try {
if (_keys[position] != null) {
list = _workspacesMap.get(_keys[position]);
}
} catch (ArrayIndexOutOfBoundsException e) {
list = null;
}
return list;
}

public long getItemId(int position) {
return position;
}

public View getView(int position, View convertView, ViewGroup parent) {
ViewGroup viewGroup = null;
int numRows = 0;

if (convertView != null) {
viewGroup = (ViewGroup) convertView;
} else {
LayoutInflater inflater = (LayoutInflater) _activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
viewGroup = (ViewGroup) inflater.inflate(R.layout.multi_workspace_layout, parent, false);

_keys = (String[]) _workspacesMap.keySet().toArray(new String[_workspacesMap.size()]);
List<WorkspaceInfo> workspaces = new ArrayList<WorkspaceInfo>();
try {
if (_keys[position] != null) {
workspaces = _workspacesMap.get(_keys[position]);
//Collections.sort(workspaces, new InfoNameComparator());
}
} catch (ArrayIndexOutOfBoundsException e) {
//
}

numRows = viewGroup.getChildCount();

//Find how many buttons are in a row.
int buttonsInRow = ((ViewGroup) viewGroup.getChildAt(0)).getChildCount();

int totalRows = 0;
int size = workspaces.size();
if (size > 0) {
totalRows = size / buttonsInRow + 1;
}

if (numRows < totalRows) {
for (int i = numRows; i < totalRows; i++) {
View view;
LayoutInflater inflater2 = (LayoutInflater) _activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (View) inflater2.inflate(R.layout.list_row_multi_ws, viewGroup, false);
viewGroup.addView(view, i);
}
} else if (numRows > totalRows) {
for (int i = numRows; i > totalRows; i--) {
viewGroup.removeViewAt(totalRows);
}
}

//Iterate over workspaces
Iterator<WorkspaceInfo> iterator = workspaces.iterator();
for (int i = 0; i < viewGroup.getChildCount(); i++) {
//Linear layout child containing buttons and textview.
ViewGroup temp = (ViewGroup) viewGroup.getChildAt(i);
for (int j = 0; j < temp.getChildCount(); j++) {
if (j == 0) {
//The letter these workspaces start with
TextView textview = (TextView) temp.getChildAt(j);
String letter = _keys[position];
textview.setText(_keys[position]);
if (i != 0 && temp.getId() != R.id.workspaces_portrait) {
textview.setVisibility(View.INVISIBLE);
} else if (i != 0) {
textview.setVisibility(View.GONE);
}
} else {
//A workspace button
Button button = (Button) temp.getChildAt(j);
if (iterator.hasNext()) {
//Get the next workspace
final WorkspaceInfo workspace = iterator.next();
//Get the title of the workspace and set as text.
String buttonText = workspace.getTitle();
button.setText(buttonText);
button.setVisibility(View.VISIBLE);
//Add OnClickListener
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//If the workspace is pending, handle the invitation.
if (workspace.getStatus() == StaticFields.PENDING_WORKSPACE) {
((SkootWorkspacesActivity) _activity).handleInvitation(workspace);
} else {
//open the workspace
((SkootWorkspacesActivity) _activity).openWorkspace(workspace);
}
}
});
button.setOnLongClickListener(new OnLongClickListener() {
public boolean onLongClick(View v) {
((SkootWorkspacesActivity) _activity).makeDeleteDialog(workspace);
return true;
}
});
} else {
button.setVisibility(View.GONE);
}
}
}
}

}
return viewGroup;
}


I add this adapter to a MergeAdapter and do setAdapter on the ListView with the MergeAdapter.

Thanks

Answer

The Best solution for your problem (ListView to lag) is Holder i.e using Holder class

Sample code

Create an object for ViewHolder class in the Adapter class Constructor

ViewHolder holder=new ViewHolder(); 

public View getView(int position, View convertView, ViewGroup parent) {
        AppInfo entry = mListAppInfo.get(position);
        ViewHolder holder = null;

        if(convertView == null) {
            LayoutInflater inflater = LayoutInflater.from(mContext);
            convertView = inflater.inflate(R.layout.layout_appinfo, null);
            holder = new ViewHolder();
            holder.ivIcon = (ImageView)convertView.findViewById(R.id.ivIcon);
            holder.tvName = (TextView)convertView.findViewById(R.id.tvName);
            convertView.setTag(holder);
        }
        else {
            holder = (ViewHolder)convertView.getTag();
        }

        holder.ivIcon.setImageBitmap(entry.getIcon());
        holder.tvName.setText(entry.getName());

        return convertView;
    }

    static class ViewHolder {
        ImageView ivIcon;
        TextView tvName;
    }
Comments