1

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;
    }
}
}
Thomas Hodges
  • 105
  • 1
  • 10
  • Have you tryed to use `getItemViewType()` and `getViewTypeCount()` with `ViewHolder` instead of your code in `getView()`? – anil Feb 17 '15 at 18:24
  • I was about to write what @anil mentioned -- you might want to check out this question here http://stackoverflow.com/questions/4777272/android-listview-with-different-layout-for-each-row – Eric Farraro Feb 17 '15 at 18:25
  • It looks like that is based on position. As I go on I want to be able to add other types based on missed payments, extra payments, penalties, etc and have them appear in the list chronologically. I am going to try bonnyz's method of using tags. I earlier was trying to implement if statements that referred back to the data, but could not work out how to link them to the convertView. – Thomas Hodges Feb 17 '15 at 18:38

3 Answers3

3

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.

bonnyz
  • 13,458
  • 5
  • 46
  • 70
1

Thanks! Bonnyz's suggestion worked. I added the following code:

Payment p = mPayments.get(position);

        if (convertView == null || convertView.getTag() != p.type) {
            if(p.type == Payment.TYPE_START) {
                convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_start, null);
                convertView.setTag(Payment.TYPE_START);
            } else{
                convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_payment, null);
                convertView.setTag(Payment.TYPE_PAYMENT);
            }

        }

I'll be experimenting with ViewHolder also. I just learned about that today.

Thomas Hodges
  • 105
  • 1
  • 10
0
public class CustomAdapter extends BaseAdapter {
String[] frName;
String[] lrName;
String[] myLocation;
Context context;
int[] imageId;
private static LayoutInflater inflater = null;


public CustomAdapter(MainActivity mainActivity, String[] fstName, String[] lstName, String[] location, int[] prgmImages) {
    super();
    context = mainActivity;
    frName = fstName;
    lrName = lstName;
    myLocation = location;
    imageId = prgmImages;
    inflater = (LayoutInflater) context.
            getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}


@Override
public int getCount() {
    // TODO Auto-generated method stub
    return 12;

}

@Override
public Object getItem(int position) {
    // TODO Auto-generated method stub
    return position;
}

@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return position;
}

public class Holder {
    TextView tv_frname, tv_lrname, tv_location, tv_fstname, tv_lstname;
    ImageView img;

}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    Holder holder = new Holder();
    if (position < frName.length) {
        convertView = inflater.inflate(R.layout.myadapterdesin, null);
        holder.tv_frname = (TextView) convertView.findViewById(R.id.frname);
        holder.tv_lrname = (TextView) convertView.findViewById(R.id.lrname);
        holder.tv_location = (TextView) convertView.findViewById(R.id.place);
        holder.tv_frname.setText(frName[position]);
        holder.tv_lrname.setText(lrName[position]);
        holder.tv_location.setText(myLocation[position]);
        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Toast.makeText(context, "You Clicked " + position, Toast.LENGTH_SHORT).show();
            }
        });
        return convertView;

    } else if (position >= frName.length) {
        convertView = inflater.inflate(R.layout.mylist, null);
        holder.img = (ImageView) convertView.findViewById(R.id.img_view);
        holder.tv_fstname = (TextView) convertView.findViewById(R.id.fstname);
        holder.tv_lstname = (TextView) convertView.findViewById(R.id.lstname);
        holder.tv_fstname.setText(frName[(position) - (frName.length)]);
        holder.tv_lstname.setText(lrName[(position) - (frName.length)]);
        holder.img.setImageResource(imageId[(position) - (frName.length)]);

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Toast.makeText(context, "You Clicked " + position, Toast.LENGTH_SHORT).show();
            }
        });
        return convertView;
    }
    convertView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            Toast.makeText(context, "You Clicked " + position, Toast.LENGTH_SHORT).show();
        }
    });
    return convertView;

}

}