dimanche 2 octobre 2016

Adding and removing items selected with checkbox in RecyclerView to an ArrayList

I'm building my first android app and am having trouble adding items to and removing items from an ArrayList when checkboxes in the RecyclerView are selected and deselected.

How it works: When the user long clicks on any of the players in the list, a checkbox becomes visible alongside each player and the toolbar with an icon to delete any selected items from the RecyclerView is shown. When a user clicks on a checkbox, that player is added to the selectionList. If a user then changes their mind and deselects a checkbox that they have previously selected, the player should be removed from the selectionList. Once the user is happy with their selection they click the delete icon, which should remove any players on the selectionList from the main playerList (nb. The playerList is populated from the SQLite database with a dbHelper).

The problems:

  1. The user is able to add players to the selectionList, but when they deselect a checkbox that has already been selected, the player is not removed.
  2. As a result of problem 1, the checkbox (which is now deselected) can once again be selected by the user and this adds a duplicate player to the selectionList.
  3. When I scroll up or down the RecyclerView, checkboxes that have been selected become deselected as they move off the screen. (I have seen a few posts on here regarding this issue but am trying to solve the first problem before delving into this as I don't know if my current adapter setup is correct).

Note: If i use the deletePlayer() method within updatePlayerStatsAdapter() it will delete the selected items successfully but the list problems described above still occur, so I have commented them out for now. Most searching done on first issue but unable to solve my problem. Any help or pointers on how to proceed or fix these issues would be great.

Screenshot Android Monitor Output

Method from StatsPlayerActivity.java class:

    /**
     * Method to update the list of selected players chosen with checkboxes and count number of
     * checkboxes selected.
     */
    public void playerCheckboxSelection(View v, int position) {
        dbHelper = new DatabaseHelper(this);

        // Get all players via DatabaseHelper class and add them to a new list.
        List<Player> playerList = dbHelper.getAllPlayers();

        Player selectedPlayer = playerList.get(position);

        // Check if the user has selected a checkbox. 
        if (((CheckBox) v).isChecked()) {
            // Add the selected player to the list.
            this.selectionList.add(selectedPlayer);

            for(Player p: selectionList) {
                Log.d("selectList1 ", p.getPlayerName());
            }

            // Increase the counter by one.
            selectionCounter += 1;
            // Update counter text in action bar.
            updateStatsToolbarCounterText(selectionCounter);
        } else {
            // TODO problem lies here. Adding to selectList is fine. Remove function works too(tried in above). Need to handle the deselect of an already checked checkbox. That will solve issue.
            // Delete the selected player from the list.
            this.selectionList.remove(selectedPlayer);

            for(Player p: selectionList) {
                Log.d("selectList2 ", p.getPlayerName());
            }

            // Decrease the counter by one.
            selectionCounter -= 1;
            // Update counter text in action bar.
            updateStatsToolbarCounterText(selectionCounter);
        }
    }

StatsPlayerAdapter:

public class StatsPlayerAdapter extends RecyclerView.Adapter<StatsPlayerAdapter.StatsPlayerViewHolder> {
    /**
     * Global variables.
     */
    private List<Player> playerList = new ArrayList<>();
    private Context mCtx;
    private StatsPlayerActivity mStatsPlayerActivity; // needed to access variables from StatsPlayerActivity class.

    /**
     * Constructor.
     */
    public StatsPlayerAdapter(List<Player> list, Context ctx) {
        this.playerList = list;
        this.mCtx = ctx;
        this.mStatsPlayerActivity = (StatsPlayerActivity) ctx;
    }

    /**
     * Create the views.
     * Inflates the row layout and initialises the ViewHolder. Once the ViewHolder is initialised
     * it manages the findViewById methods. It finds the views once and recycles them to
     * avoid repeated calls.
     */
    @Override
    public StatsPlayerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // Create new view, specifying the layout that each should use.
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item_stats_player_card, parent, false);
        // Create new custom ViewHolder.
        StatsPlayerViewHolder spvh = new StatsPlayerViewHolder(v, mCtx, mStatsPlayerActivity);
        return spvh;
    }

    /**
     * Uses the ViewHolder constructed in onCreateViewHolder() to populate the current row of the
     * RecyclerView with data.
     */
    @Override
    public void onBindViewHolder(StatsPlayerViewHolder holder, int position) {
        // Get data at this position from data set.
        Player singlePlayer = playerList.get(position);

        // Replace the contents of the view with the data from above.
        holder.txtStatsPlayerCardPlayerId.setText(String.valueOf(singlePlayer.getId()));
        holder.txtStatsPlayerCardPlayerName.setText(singlePlayer.getPlayerName());
        holder.txtStatsPlayerCardPlayerWins.setText(String.valueOf(singlePlayer.getPlayerWins()));
        holder.txtStatsPlayerCardPlayerLosses.setText(String.valueOf(singlePlayer.getPlayerLosses()));
        holder.txtStatsPlayerCardPlayerDraws.setText(String.valueOf(singlePlayer.getPlayerDraws()));

        // Using boolean from StatsPlayerActivity class. If false, don't show checkboxes. If true,
        // show checkboxes to visible and make sure they are set to false by default.
        if(mStatsPlayerActivity.isInActionMode == false) {
            holder.chkbxStatsPlayerCard.setVisibility(View.GONE);
        } else {
            holder.chkbxStatsPlayerCard.setVisibility(View.VISIBLE);
            holder.chkbxStatsPlayerCard.setChecked(false);
        }
    }

    /**
     * Return the number of items in our data set.
     */
    @Override
    public int getItemCount() {
        return playerList.size();
    }

    /**
     * Custom ViewHolder. Inner class to hold a reference to each item of RecyclerView.
     * The RecyclerView uses a ViewHolder to store the references to the relevant views for one
     * entry in the RecyclerView. It avoids all the findViewById method calls in the
     * adapter to find the views to be filled with data.
     */
    public static class StatsPlayerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        /**
         * Variables.
         */
        private Context ctx;
        private StatsPlayerActivity statsPlayerActivity;
        private TextView txtStatsPlayerCardPlayerId;
        private TextView txtStatsPlayerCardPlayerName;
        private TextView txtStatsPlayerCardPlayerWins;
        private TextView txtStatsPlayerCardPlayerLosses;
        private TextView txtStatsPlayerCardPlayerDraws;
        private CardView cvStatsPlayerCard;
        private CheckBox chkbxStatsPlayerCard;

        /**
         * Constructor.
         */
        public StatsPlayerViewHolder(View itemView, Context ctx, StatsPlayerActivity statsPlayerActivity) {
            super(itemView);
            this.ctx = ctx;
            this.statsPlayerActivity = statsPlayerActivity;
            // Get reference to views defined in stats player card xml layout.
            txtStatsPlayerCardPlayerId = (TextView) itemView.findViewById(R.id.txtStatsPlayerCardPlayerId);
            txtStatsPlayerCardPlayerName = (TextView) itemView.findViewById(R.id.txtStatsPlayerCardPlayerName);
            txtStatsPlayerCardPlayerWins = (TextView) itemView.findViewById(R.id.txtStatsPlayerCardPlayerWins);
            txtStatsPlayerCardPlayerLosses = (TextView) itemView.findViewById(R.id.txtStatsPlayerCardPlayerLosses);
            txtStatsPlayerCardPlayerDraws = (TextView) itemView.findViewById(R.id.txtStatsPlayerCardPlayerDraws);

            // If player long clicks any of the cards in the recyclerView, it will invoke the
            // overridden onLongClick method inside the StatsPlayerActivity class.
            cvStatsPlayerCard = (CardView) itemView.findViewById(R.id.cvStatsPlayerCard);
            cvStatsPlayerCard.setOnLongClickListener(statsPlayerActivity);

            chkbxStatsPlayerCard = (CheckBox) itemView.findViewById(R.id.chkbxStatsPlayerCard);
            chkbxStatsPlayerCard.setOnClickListener(this);
        }

        /**
         * On Click method.
         */
        @Override
        public void onClick(View v) {
            // Call the playerCheckboxSelection method from the StatsPlayerActivity class.
            statsPlayerActivity.playerCheckboxSelection(v, getAdapterPosition());
        }
    }

    public void updateStatsPlayerAdapter(List<Player> list) {
//        DatabaseHelper dbHelper = new DatabaseHelper(mCtx);

        // playerList oorrectly shows all players in db.
        for(Player p: playerList) {
            Log.d("playerList1 ", p.getPlayerName());
        }

        // For each player in list given in the parameter, remove the player from the playerList.
        for (Player player : list) {
            this.playerList.remove(player);
//            dbHelper.deletePlayer(player);
            Log.d("selectList3  ", player.getPlayerName());
        }

        // removal of selected list not working, playerList2 == playerList1
        for(Player p: playerList) {
            Log.d("playerList2 ", p.getPlayerName());
        }

        // TODO Doesnt update? 
        notifyDataSetChanged();
    }


}




Aucun commentaire:

Enregistrer un commentaire