0

I designed a scenario which, according to my understanding of Java, should have worked out fine but unfortunately didn't. The scenario is explained in code:

ListViewAdapter

public final class ListViewAdapter extends BaseAdapter {

    private Context context;
    private RadioGroup[] radioGroups;
    private List<String> listOfData;

    public OneForAllListViewAdapter(Context context, List<String> listOfData) {
        super();
        this.context = context;
        this.radioGroups = new RadioGroup[listOfData.size()];
        this.listOfData = listOfData;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final String timelyOfferedStr = "Yes";
        final String lateOfferedStr = "Yes but late";
        final String notOfferedStr = "No";
        final String pName = listOfData.get(position);

        if(convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.one_for_all_list_item, parent, false);
        }

        TextView pNameTextView = (TextView) convertView.findViewById(R.id.one_for_all_p_name_TextView);
        RadioButton timelyOffered = (RadioButton) convertView.findViewById(R.id.one_for_all_timely_offered);
        RadioButton lateOffered = (RadioButton) convertView.findViewById(R.id.one_for_all_late_offered);
        RadioButton notOffered = (RadioButton) convertView.findViewById(R.id.one_for_all_not_offered);

        this.radioGroups[position] = (RadioGroup) convertView.findViewById(R.id.one_for_all_radio_group);

        pNameTextView.setText(pName);
        timelyOffered.setText(timelyOfferedStr);
        lateOffered.setText(lateOfferedStr);
        notOffered.setText(notOfferedStr);

        return convertView;
    }

    @Nullable
    public ThatStatus[] getThoseStatuses()
    {
        ThatStatus[] thoseStatuses = new ThatStatus[radioGroups.length];

        for(int i=0; i<radioGroups.length; i++) {
            int selectedRadioButton = radioGroups[i].getCheckedRadioButtonId();

            switch (selectedRadioButton) {
                case R.id.one_for_all_timely_offered:
                    thoseStatuses [i] = ThatStatus.TimelyOffered;
                    break;
                case R.id.one_for_all_late_offered:
                    thoseStatuses [i] = ThatStatus.Offered;
                    break;
                case R.id.one_for_all_not_offered:
                    thoseStatuses [i] = ThatStatus.NotOffered;
                    break;
                default:
                    return null;
            }
        }

        return thoseStatuses;
    }
}

The important thing to note in above code is this line:

this.radioGroups[position] = (RadioGroup) convertView.findViewById (R.id.one_for_all_radio_group);

I am saving all the RadioGroups in an array of RadioGroup, and in getThoseStatuses() I am trying to get the checked RadioButtons from those RadioGroups. But radioGroups[i].getCheckedRadioButtonId() always returns me -1.

Am I missing some Java concept? What seems to be the problem here?

Bugs Happen
  • 2,169
  • 4
  • 33
  • 59

2 Answers2

0

This is a design flaw. You should not store views in your model. Store data in your model. Instead of

this.radioGroups[position] = (RadioGroup) convertView.findViewById(R.id.one_for_all_radio_group);

set the checked status of the RadioGroup according to your model:

model = getItem(position);
switch(model.offered) {
  case 0:
    radioGroup.check(R.id.one_for_all_timely_offered);
    break;
  case 1:
    radioGroup.check(R.id.one_for_all_late_offered);
    break;
  ...

Keep all your data in the view model.

Consider extending ArrayListAdapter. Access the items of the adapter instead of the input data.

JanPl
  • 794
  • 6
  • 19
0

Try to create a View Houlder Pattern for your Apapter.

Eg : change your getView to

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

            Viewhoulder viewHoulder = null;
            final String timelyOfferedStr = "Yes";
            final String lateOfferedStr = "Yes but late";
            final String notOfferedStr = "No";
            final String pName = listOfData.get(position);
            if(convertView == null) {
                convertView = LayoutInflater.from(context).inflate(R.layout.one_for_all_list_item, parent, false);
                viewHoulder  = new Viewhoulder ();
                viewHoulder.pNameTextView = (TextView) convertView.findViewById(R.id.one_for_all_p_name_TextView);
                viewHoulder.timelyOffered = (RadioButton) convertView.findViewById(R.id.one_for_all_timely_offered);
                viewHoulder.lateOffered = (RadioButton) convertView.findViewById(R.id.one_for_all_late_offered);
                viewHoulder.notOffered = (RadioButton) convertView.findViewById(R.id.one_for_all_not_offered);
                viewHoulder.radioGroup = (RadioGroup) convertView.findViewById(R.id.one_for_all_radio_group);
            }
            else
              viewHoulder  = (Viewhoulder )convertView .getTag();
            this.radioGroups[position] = viewHoulder .radioGroup ;
            viewHoulder . pNameTextView.setText(pName);
            viewHoulder .timelyOffered.setText(timelyOfferedStr);
            viewHoulder .lateOffered.setText(lateOfferedStr);
            viewHoulder .notOffered.setText(notOfferedStr);
            return convertView;
        }

And create this Viewhoulder class inside your adapter

static class Viewhoulder {
   private TextView pNameTextView;
   private RadioButton timelyOffered;
   private RadioButton lateOffered ;
   private RadioButton notOffered;
   private RadioGroup radioGroup;
}
J.R
  • 2,113
  • 19
  • 21
  • I am sorry for late reply, how is this different than my solution? You are creating an extra class for saving views, I am saving them in array. – Bugs Happen Jul 28 '15 at 19:18
  • It is not just a class to store data. 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. – J.R Jul 29 '15 at 04:06
  • okay, thanks for explaining the performance thing. I'll try it out. – Bugs Happen Jul 29 '15 at 05:49
  • also, are you suggesting that we should use View Holder design pattern in every `BaseAdapter` class, to improve performance? – Bugs Happen Jul 29 '15 at 05:51
  • Yes, for performance and memory management. Definitely you can view the difference. – J.R Jul 29 '15 at 05:56
  • and this ViewHolder class has to be static? if yes, why? – Bugs Happen Jul 29 '15 at 07:06
  • If the ViewHolder class is static ,it won't leak the Adapter when you have large number of collections or view to display. – J.R Jul 29 '15 at 07:28