androidlistviewadapterconvertview

multiple xml views with convertView android


I am trying to write a ListView adapter that will pass a view based on one of several xml files depending on an attribute of the data that I am creating a View for. My code works fine, except when I try to use convertView to speed up the process. No matter how I try to use it, I either crash my program or else get strange output. I understand why this would be a problem for convertView, but I strongly suspect that I can still make this work. Can anyone advise me on how I might fix my code? (right now I am using convertView as the name of the view that I return, even though I don't have the 'if (convertView==null)' routine working properly)

public class PaymentListFragment extends ListFragment {

private ArrayList<Payment> mPayments;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getActivity().setTitle(R.string.payment_schedule_title);
    mPayments = PaymentSchedule.get(getActivity()).getPayments();
    PaymentAdapter adapter = new PaymentAdapter(mPayments);
    setListAdapter(adapter);
}


private class PaymentAdapter extends ArrayAdapter<Payment> {

    public PaymentAdapter(ArrayList<Payment> payments) {
        super(getActivity(), 0, payments);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        Payment p = mPayments.get(position);
        //normal
        //if (convertView == null) {
        //cant work out how to use convertview conditional without screwing up project
        //it would speed it up to fix this however
        if (p.type == Payment.TYPE_START) {


            convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_start, null);

            TextView remainDisplay =
                    (TextView) convertView.findViewById(R.id.remainDisplayStart);
            remainDisplay.setText(p.getRemainString());
            TextView paymentDate =
                    (TextView) convertView.findViewById(R.id.paymentDateStart);
            paymentDate.setText(p.getDateString());
            TextView paymentDisplay =
                    (TextView) convertView.findViewById(R.id.paymentDisplayStart);
            paymentDisplay.setText(p.getDefaultPaymentString());
            TextView aprDisplay =
                    (TextView) convertView.findViewById(R.id.aprDisplayStart);
            aprDisplay.setText(p.getInterestRate() * 1200 + "%");
        } else {
             //if (convertView == null) {
                convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_payment, null);
            //}
            TextView paymentDate =
                    (TextView) convertView.findViewById(R.id.paymentDate);
            paymentDate.setText(p.getDateString());
            TextView paymentDisplay =
                    (TextView) convertView.findViewById(R.id.paymentDisplay);
            paymentDisplay.setText(p.getPaymentString());
            TextView principalDisplay =
                    (TextView) convertView.findViewById(R.id.principalDisplay);
            principalDisplay.setText(p.getPrincipalString());
            TextView interestDisplay =
                    (TextView) convertView.findViewById(R.id.interestDisplay);
            interestDisplay.setText(p.getInterestString());
            TextView remainDisplay =
                    (TextView) convertView.findViewById(R.id.remainDisplay);
            remainDisplay.setText(p.getRemainString());
        }
        //}
        return convertView;
    }
}
}

Solution

  • You can do the following trick:

    1. Always attach a tag to you convertView when you create it (setTag()) specifying the type of the layout (in your case R.layout.list_item_start or R.layout.list_item_payment).

    2. when you check if convertView != null you need also to check if the type specified by convertView.getTag() is the same of the layout that you are updating in order to avoid the inflate operation properly because:

      • if the types are different you need to overwrite convertView with a new inflate operation, because you need to create the proper layout type.
      • if the types are equal you can simply update the layout without the inflate operation

    You can also improve the whole code by adopting the ViewHolder pattern.