When trying to add new element in RecyclerView, some items are duplicated

Oscar :

I've created a game where the user needs to enter the players' name in a recycler view in order to start the game.
My issue is that when I try adding new players, every 8 or 9 players, the first names entered are duplicated.
I've tried searching online as to why but was unsuccessful in finding a solution and really can't see where the problem lies.
Also, when I modify the duplicated names, it also changed every instance of that name in the recycler view.
The activity works fine, when the game is started, every name entered is in the game with no duplicates.

EDIT: I've added holder.playerName.getText().clear(); in onBindViewHolder in the adapter class, that corrected the duplication problem but created another one: I now have empty EditTexts with no hints (where the EditText should hint the player number)

EDIT 2: Putting the holder.playerName.getText().clear() line under the holder.playerName.setHint(players.get(position).getName()) line in the onBindViewHolder method did the trick! Thanks!

Here is the code for the activity:

 public class PlayersNameScreen extends AppCompatActivity {

  public PlayerMenu playerMenu;                           // A PlayerMenu used to populate the screen when started
  public static PlayerMenu playerMenu1;                   // A static PlayerMenu to store all the players entered on this screen and access it on the next

  private RecyclerView listOfPlayers;                     // The recycler view where the players can see, add and enter other players
  private ListOfPlayersAdapter listOfPlayersAdapter;      // The adapter for the recycler view

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      initializeScreen();
  }

  /**
   * Sets the contents of the screen
   */
  private void initializeScreen() {

      setContentView(R.layout.activity_players_name_screen);

      listOfPlayers = findViewById(R.id.playerNames);
      // The button used to add a player
      FloatingActionButton addPlayer = findViewById(R.id.addPlayer);

      // Start the game with the new players entered, filtering the menu as well
      // The button to start the game
      Button startGame = findViewById(R.id.Booze);
      startGame.setOnClickListener(view -> {
          playerMenu1 = new PlayerMenu();
          playerMenu1.removeAllPlayers();
          playerMenu1.addAllPlayers(playerMenu.getPlayers());
          playerMenu1.filter();
          goToCardScreen();
      });

      playerMenu = new PlayerMenu();

      // Set the default view of the list
      setListOfPlayersView(playerMenu.getPlayers());

      // Adds a row to the list and a player to the menu, scrolls to the new player entered
      addPlayer.setOnClickListener((View view) -> {
          playerMenu.addPlayer(playerMenu.size());
          listOfPlayersAdapter.notifyItemInserted(playerMenu.size() - 1);
          listOfPlayers.smoothScrollToPosition(playerMenu.size() - 1);
      });

  }

  /**
   * Creates the list of all the players (the view)
   * @param playerz the list of the players
   */
  void setListOfPlayersView(ArrayList<Player> playerz) {
      listOfPlayersAdapter = new ListOfPlayersAdapter(playerz);
      RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());

      listOfPlayers.setLayoutManager(layoutManager);
      listOfPlayers.setItemAnimator(new DefaultItemAnimator());
      listOfPlayers.setAdapter(listOfPlayersAdapter);

  }

  /**
   * Before launching the game, check that the names are correct
   */
  private void goToCardScreen() {
      Set<String> set = new HashSet<>(playerMenu1.getPlayersNames());
      boolean playersNameOK = true;
      boolean playersEntered = true;
      boolean enoughPlayers = true;

      if (set.size() < playerMenu1.getPlayers().size()) {
          // Shows a message that the player entered duplicated names
          playersNameOK = false;
      }

      if (set.isEmpty()) {
          // Shows a message saying they need to enter players
          playersEntered = false;
      }

      if (set.size() == 1) {
          // Shows a message showing that there aren't enough players
          enoughPlayers = false;
      }

      if (playersNameOK && playersEntered && enoughPlayers) {
          createWaiver(); --> eventually leads to next activity
      }
  }
}

Here's the code of the adapter

 public class ListOfPlayersAdapter extends RecyclerView.Adapter<ListOfPlayersAdapter.MyViewHolder>{

  private ArrayList<Player> players; // The array to old every player entered

  @NonNull
  @Override
  public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
      View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.player_name_row, parent, false);
      return new MyViewHolder(itemView);
  }

  @Override
  public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
      int x = holder.getLayoutPosition();
      // If a real name was entered (names that don't include the string <player>), set the text of the EditText to the name of the player
      if (!players.get(x).getName().contains("Player")){
          holder.playerName.setText(players.get(x).getName());
      }
      else {
          // Keep hinting the player number (aka Player x)
          holder.playerName.setHint(players.get(position).getName());
          holder.playerName.getText().clear();
      }
  }
      @Override
  public int getItemCount() {
      return players.size();
  }

  ListOfPlayersAdapter(ArrayList<Player> players) {
      this.players = players;
  }

  class MyViewHolder extends RecyclerView.ViewHolder {

      private EditText playerName;

      MyViewHolder(View itemView) {
          super(itemView);
          playerName = itemView.findViewById(R.id.playerInput);

          playerName.addTextChangedListener(new TextWatcher() {
              @Override
              public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

              @Override
              public void onTextChanged(CharSequence s, int start, int before, int count) {
                  Player playerBis = new Player(s.toString());
                  players.set(getAdapterPosition(),playerBis);
              }

              @Override
              public void afterTextChanged(Editable s) {
              }
          });
      }
  }
 }

Here is the code of the player menu:

 class PlayerMenu {
  private ArrayList<Player> players; // List to store every player

  PlayerMenu() {
      // Creating and adding the players to the menu
      players = new ArrayList<>();

      Player player1 = new Player("Player 1");
      Player player2 = new Player("Player 2");
      Player player3 = new Player("Player 3");

      players.add(player1);
      players.add(player2);
      players.add(player3);
  }

  /**
   *
   * @param i The position of the player in the list
   * @return The name of the player
   */
  String getPlayer(int i) {
      return players.get(i).getName();
  }

  /**
   * Method to add a player in the menu
   */
  void addPlayer(int position){
      Player player = new Player("Player" + " " + (players.size() + 1));
      players.add(position, player);
  }

  /**
   * Method to add all players from an ArrayList to the players array list
   * @param playerz The ArrayList we want to get the players from
   */
  void addAllPlayers(ArrayList<Player> playerz) {
      players.addAll(playerz);
  }

  /**
   * Method to remove all players from the list
   */
  void removeAllPlayers() {
      players.clear();
  }

  /**
   * To see the list of players
   * @return the list of all the players
   */
  ArrayList<Player> getPlayers() {
      return players;
  }

  /**
   * Remove from the list of players all those who are nameless (aka Player i)
   */
  void filter() {
      players.removeIf(player -> player.getName().toLowerCase().contains("player")) || player.getName().isEmpty()));
  }

  /**
   * Size of the list
   * @return the size of the list of players
   */
  public int size() {
      return players.size();
  }
 }

When the activity screen loads and when we press on the "+" button

Adding a new player called Bob, and scrolling down: Bob is duplicated

If we add a new player John (at the top)...

...and press on the "+" button, John is also duplicated

If we keep pressing the "+" button, every 6-9 times, the names entered are duplicated

If we replace one of the player's name (here John) with another name (Karen)...

... and scroll back up, we can see that some instances of John are replaced with karen

Bhoomi :

Try adding below code in your bindviewholder method:

     @Override
  public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
      int x = holder.getLayoutPosition();
      // If a real name was entered (names that don't include the string <player>), set the text of the EditText to the name of the player
      if (!players.get(x).getName().contains("Player")){
          holder.playerName.setText(players.get(x).getName());
      }
      else {
          holder.playerName.setText("")
          // Keep hinting the player number (aka Player x)
          holder.playerName.setHint(players.get(position).getName());
      }
  }

holder.playerName.setText("") You need to add some value in else condition also, as recyclerview recycles the items and hence you are getting duplicate items.

Hope this helps!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=143438&siteId=1