The Rationalist
The Rationalist

Reputation: 753

I am losing values from ListView items that have been scrolled out of view

I have an app that gathers points from checkboxes in a listview. The checkboxes are dynamically added along with the items of the listview. Each time a checkbox is clicked, I add points to a total. The manner in which I do this works fine as long as all the list items fit on the screen. When the list gets long enough to cause it to scroll, I lose the values I had previously checked when I scroll down the list. So, my scrolling the list causes the points to reset. I feel pretty confident it has something to do with losing focus from the checkboxes and/or gaining focus from the click to the listview itself, that causes this reset in points.

IMPORTANT EDIT: Ok, so it doesn't actually take a simple click and SLIGHT scroll of the listview to cause this to happen. I have to actually get the previous CHECKBOX scrolled out of view just enough to make the points reset. WTF?

Here's some code...

Here is my entire custom adaptor that handles the checkbox:

public class ScoreListAdapter extends BaseAdapter {

    private ArrayList<ScoringInfo> data;
    Context c;
    ScoringInfo scr;

    ScoreListAdapter (ArrayList<ScoringInfo> data, Context c){
        this.data = data;
        this.c = c;
    }

    public int getCount() {
        // TODO Auto-generated method stub
        return data.size();
    }

    public Object getItem(int pos) {
        // TODO Auto-generated method stub
        return data.get(pos);
    }

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

    public View getView(int pos, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
         View v = convertView;

         if (v == null)
         {
            LayoutInflater vi = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.score_list_row, null);
         }

           TextView subtaskView = (TextView)v.findViewById(R.id.subtask);
           TextView maxPointsView = (TextView)v.findViewById(R.id.max_points);

           scr = data.get(pos);
           subtaskView.setText(scr.subtask);
           maxPointsView.setText("Points: " + Integer.toString(scr.maxPoints));

           final CheckBox checkBox = (CheckBox) v.findViewById(R.id.score_box);
           checkBox.setTag(R.string.subtask_num, scr.subtaskNum);
           checkBox.setTag(R.string.score, scr.maxPoints);
           checkBox.setOnClickListener(new OnClickListener() {
               public void onClick(View v) {
                   int subNum = Integer.parseInt(checkBox.getTag(R.string.subtask_num).toString());
                   int score = (Integer) checkBox.getTag(R.string.score);
                   if (((CheckBox)v).isChecked()) {

                       score =(Integer) checkBox.getTag(R.string.score);
                       Challenge.subtaskScores.put(subNum, score);
                       scr.addToTotalPoints(score);
                       updatePoints(scr.getTotalPoints());
                   }
                   else {
                       if (Challenge.subtaskScores.containsKey(subNum))
                           Challenge.subtaskScores.remove(subNum);
                       scr.addToTotalPoints(-score);
                       updatePoints(scr.getTotalPoints());
                   }
               }
           });
        return v;
    }

    public void updatePoints(int total){
        TextView scrUpdate = (TextView) ((Activity)c).findViewById(R.id.curr_score_view);
        Challenge.totalPoints1 = total;
        int grandTotal = Challenge.totalPoints1 + Challenge.totalPoints2;
        scrUpdate.setText("Current Score: " + grandTotal);
    }
}

Here is what I feel is the relevant code from Challenge.class:

public void createScoringList() {
        // Builds two lists: one for the tasks that do not allow partial points, and
        // another for the tasks that DO allow partial points. The lists are stacked
        // on top of each other.  This was the only way I could come up with to present
        // two types of layouts for the two types of point input. This may need to be
        // reconsidered.
        ListView scoreList = (ListView) findViewById(R.id.score_list);
        ListView scoreListPartial = (ListView) findViewById(R.id.score_list_partial);
        ArrayList<ScoringInfo> objList = new ArrayList<ScoringInfo>();  
        ArrayList<ScoringInfo> objListPartial = new ArrayList<ScoringInfo>();
        ScoringInfo scrInfo;    
        // The ScoringInfo object holds the various fields that are associated with each subtask.

        infoView = (TextView) findViewById(R.id.chall_team_config_show);
        infoView.setText(chall_name + " (id: " + challenge_id + ")\nTeam: " + team_num +
                "\nConfiguration: " + randomConfig);

        for (int i = 0; i < subTaskList.size(); i++) {
            subtask_num = subTaskList.get(i).subtask_num;
            max_points = subTaskList.get(i).max_points;
            partial_points_allowed = subTaskList.get(i).partial_points_allowed;
            task_name = subTaskList.get(i).task_name;

            scrInfo = new ScoringInfo();
            scrInfo.setMaxPoints(max_points);
            scrInfo.setSubtask(task_name);
            scrInfo.setSubtaskNum(subtask_num);

            if (partial_points_allowed == 1)
                objListPartial.add(scrInfo);
            else
                objList.add(scrInfo);
        }
        // There is a custom adapter for both possible lists should the challenge need it.
        scoreList.setAdapter(new ScoreListAdapter(objList , this));
        scoreListPartial.setAdapter(new ScoreListAdapter2(objListPartial, this));   
    }

No doubt I forgot something. If there's confusion over my question, please ask for clarification. This is driving me nuts, and keeping me up all night.

Upvotes: 0

Views: 391

Answers (1)

Axxiss
Axxiss

Reputation: 4789

Your problem is as stated by @Patrick on the first comment that your are not saving the CheckBox state. You will need to save it to somewhere, a boolean array for example.

Then when you recreate the view you will get the saved value from the array and check/uncheck the CheckBox.

Upvotes: 1

Related Questions