Skip to content
Advertisement

How to display already checked checkboxes in recyclerview, on activity start-up(many to many relationship)

Each “Note” is differently “added” to “Folders” or should I say, different checked “Folders” for each “Note”.

When I check the “Folder”, go back to previous Notes activity with back button, then open the same “Note” to go to “Add to Folders Activity” and add the “Note” to Folders, it should remember that previously checked “Folder” and recheck it.

I have already implemented that functionality, inside onBindViewHolder and in FolderHolder(RecyclerView Holder).

The problem is when multiple “Folders” exist in recyclerview when I uncheck the checkbox, then scroll down, then back up, the unchecked folder rechecks itself as it was.

I understand that onBindViewHolder gets called every time on scroll and recycling views thus checked “Folder” gets rechecked on scroll.

I want to check the already before checked folders, on activity start-up, just like now, but without rechecking them on scroll.

Please can you suggest me a code to this? I would really appreciate this!

My recyclerview adapter:

public class FoldersAddToFoldersAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private final Context context;

    private final ArrayList<Folder> folders;

    private final List<Folder> checkedFolders;

    private final Note note;

    private final FoldersDAO foldersDao;

    private final NotesFoldersJoinDAO notesFoldersJoinDao;

    public FoldersAddToFoldersAdapter(ArrayList<Folder> folders, List<Folder> checkedFolders, Note note, Context context,
                                      FoldersDAO foldersDao, NotesFoldersJoinDAO notesFoldersJoinDao) {
        this.folders = folders;
        this.checkedFolders = checkedFolders;
        this.note = note;
        this.context = context;
        this.foldersDao = foldersDao;
        this.notesFoldersJoinDao = notesFoldersJoinDao;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(context).inflate(R.layout.folder_add_to_folders_layout, parent, false);
        return new FolderHolder(v, this, notesFoldersJoinDao);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        final FolderHolder folderHolder = (FolderHolder) holder;
        final Folder folder = getFolder(position);
        if (folder != null) {
            //[..]

            folderHolder.setData(note, folder);


            // **THIS IS THE CODE WHICH CHECKS THE FOLDERS, WHICH I WAS SAYING ABOUT.** 
            for (Folder checkedFolder : checkedFolders) {
                if (checkedFolder.getId() == folder.getId()) {
                    folder.setChecked(true);
                }
            }
            folderHolder.checkBoxAddToFolders.setChecked(folder.isChecked());
        }
    }

    public void addCheckedFolder(Folder folder) {
        checkedFolders.add(folder);
    }

    public void removeCheckedFolder(Folder folder) {
        checkedFolders.remove(folder);
    }


    public static class FolderHolder extends RecyclerView.ViewHolder {

        CheckBox checkBoxAddToFolders;

        FoldersAddToFoldersAdapter adapter;

        Note note;

        Folder folder;

        NotesFoldersJoinDAO notesFoldersJoinDao;

        public FolderHolder(@NonNull View itemView, FoldersAddToFoldersAdapter adapter, NotesFoldersJoinDAO notesFoldersJoinDao) {
            super(itemView);
            checkBoxAddToFolders = itemView.findViewById(R.id.checkbox_add_to_folders);
            this.notesFoldersJoinDao = notesFoldersJoinDao;
            this.adapter = adapter;


            // THIS IS ALSO IMPORTANT FOR CHECKBOX.
            checkBoxAddToFolders.setOnClickListener(v -> {
                boolean isChecked = checkBoxAddToFolders.isChecked();
                NoteFolderJoin noteFolderJoin = new NoteFolderJoin(note.getId(), folder.getId());
                if (isChecked) {
                    folder.setChecked(true);
                    adapter.addCheckedFolder(folder);
                    notesFoldersJoinDao.insertNoteFolderJoin(noteFolderJoin);
                } else {
                    folder.setChecked(false);
                    adapter.removeCheckedFolder(folder);
                    notesFoldersJoinDao.deleteNoteNoteFolderJoin(noteFolderJoin);
                }
            });

        public void setData(Note note, Folder folder) {
            this.note = note;
            this.folder = folder;
        }
    }
} 

My Activity that have the recyclerview:

public class AddToFoldersActivity extends AppCompatActivity {

    public static final String NOTE_EXTRA_KEY = "note_id";

    private RecyclerView foldersListRv;

    private FoldersDAO folderDao;

    private FoldersAddToFoldersAdapter foldersAdapter;

    private Note note;

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_to_folders);
        MaterialToolbar topAppBar = findViewById(R.id.top_app_bar_add_to_folders);
        
        foldersListRv = findViewById(R.id.folder_list_add_to_folders);
        folderDao = NotesDB.getInstance(this).foldersDAO();
        
        int smallestScreenWidth = getResources().getConfiguration().smallestScreenWidthDp;
        NotesDAO notesDAO = NotesDB.getInstance(this).notesDAO();

        int id = getIntent().getExtras().getInt(NOTE_EXTRA_KEY, 0);
        note = notesDAO.getNoteById(id);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);

        foldersListRv.setLayoutManager(layoutManager);

        loadFolders();

        topAppBar.setNavigationOnClickListener(view -> finish());
    }

    private void loadFolders () {
        NotesFoldersJoinDAO notesFoldersJoinDao = NotesDB.getInstance(this).notesFoldersJoinDAO();
        List<Folder> folderList = folderDao.getAllFolders();
        List<Folder> checkedFolderList = notesFoldersJoinDao.getFoldersFromNote(note.getId());
        ArrayList<Folder> folders = new ArrayList<>(folderList);
        this.foldersAdapter = new FoldersAddToFoldersAdapter(folders, checkedFolderList, note, this, folderDao, notesFoldersJoinDao);
        this.foldersListRv.setAdapter(foldersAdapter);
    }

My “Folder” Room db Entity:

@Entity(tableName = "folders")
public class Folder {
    @ColumnInfo(name = "folderId")
    @PrimaryKey
    private int id;

    @ColumnInfo(name = "folderName")
    private String folderName;

    //The checked state gets saved as a room db column, in each folder.
    private boolean checked;

    public Folder() {
    }

    public String getFolderName() {
        return folderName;
    }

    public void setFolderName(String folderName) {
        this.folderName = folderName;
    }
    
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    //From this method, it gets and returns the checked state of the checkbox.
    public boolean isChecked() {
        return checked;
    }

    //And from this method, it sets the checked state of the checkbox.
    public void setChecked(boolean checked) {
        this.checked = checked;
    }
}

I removed some code of course because it would make this question too lengthy.

Advertisement

Answer

I solved it finally! I moved the:

for (Folder checkedFolder : checkedFolders) {
    if (checkedFolder.getId() == folder.getId()) {
        folder.setChecked(true);
    }
}

from onBindViewHolder to the Activity that have the recyclerview(AddToFoldersActivity) and modified it a bit to fit in:

for (Folder checkedFolder : checkedFolderList) {
    for (Folder folder : folderList) {
        if (checkedFolder.getId() == folder.getId()) {
            folder.setChecked(true);
        }
    }
}

The Adapter(FoldersAddToFoldersAdapter):

public class FoldersAddToFoldersAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private final Context context;

    private final ArrayList<Folder> folders;

    private final List<Folder> checkedFolders;

    private final Note note;

    private final FoldersDAO foldersDao;

    private final NotesFoldersJoinDAO notesFoldersJoinDao;

    public FoldersAddToFoldersAdapter(ArrayList<Folder> folders, List<Folder> checkedFolders, Note note, Context context,
                                      FoldersDAO foldersDao, NotesFoldersJoinDAO notesFoldersJoinDao) {
        this.folders = folders;
        this.checkedFolders = checkedFolders;
        this.note = note;
        this.context = context;
        this.foldersDao = foldersDao;
        this.notesFoldersJoinDao = notesFoldersJoinDao;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(context).inflate(R.layout.folder_add_to_folders_layout, parent, false);
        return new FolderHolder(v, this, notesFoldersJoinDao);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        final FolderHolder folderHolder = (FolderHolder) holder;
        final Folder folder = getFolder(position);
        if (folder != null) {
            //[..]

            folderHolder.setData(note, folder);

            /* Moved code from here...
            for (Folder checkedFolder : checkedFolders) {
                if (checkedFolder.getId() == folder.getId()) {
                    folder.setChecked(true);
                }
            }
            */
            folderHolder.checkBoxAddToFolders.setChecked(folder.isChecked());
        }
    }

    public void addCheckedFolder(Folder folder) {
        checkedFolders.add(folder);
    }

    public void removeCheckedFolder(Folder folder) {
        checkedFolders.remove(folder);
    }


    public static class FolderHolder extends RecyclerView.ViewHolder {

        CheckBox checkBoxAddToFolders;

        FoldersAddToFoldersAdapter adapter;

        Note note;

        Folder folder;

        NotesFoldersJoinDAO notesFoldersJoinDao;

        public FolderHolder(@NonNull View itemView, FoldersAddToFoldersAdapter adapter, NotesFoldersJoinDAO notesFoldersJoinDao) {
            super(itemView);
            checkBoxAddToFolders = itemView.findViewById(R.id.checkbox_add_to_folders);
            this.notesFoldersJoinDao = notesFoldersJoinDao;
            this.adapter = adapter;

            checkBoxAddToFolders.setOnClickListener(v -> {
                boolean isChecked = checkBoxAddToFolders.isChecked();
                NoteFolderJoin noteFolderJoin = new NoteFolderJoin(note.getId(), folder.getId());
                if (isChecked) {
                    folder.setChecked(true);
                    adapter.addCheckedFolder(folder);
                    notesFoldersJoinDao.insertNoteFolderJoin(noteFolderJoin);
                } else {
                    folder.setChecked(false);
                    adapter.removeCheckedFolder(folder);
                    notesFoldersJoinDao.deleteNoteNoteFolderJoin(noteFolderJoin);
                }
            });

        public void setData(Note note, Folder folder) {
            this.note = note;
            this.folder = folder;
        }
    }
} 

And moved the code to Activity(AddToFoldersActivity):

public class AddToFoldersActivity extends AppCompatActivity {

    public static final String NOTE_EXTRA_KEY = "note_id";

    private RecyclerView foldersListRv;

    private FoldersDAO folderDao;

    private FoldersAddToFoldersAdapter foldersAdapter;

    private Note note;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_to_folders);
        MaterialToolbar topAppBar = findViewById(R.id.top_app_bar_add_to_folders);
        
        foldersListRv = findViewById(R.id.folder_list_add_to_folders);
        folderDao = NotesDB.getInstance(this).foldersDAO();
        
        NotesDAO notesDAO = NotesDB.getInstance(this).notesDAO();

        int id = getIntent().getExtras().getInt(NOTE_EXTRA_KEY, 0);
        note = notesDAO.getNoteById(id);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);

        foldersListRv.setLayoutManager(layoutManager);

        //This is where the code really ends up.
        loadFolders();

        topAppBar.setNavigationOnClickListener(view -> finish());
    }

    //The loadFolders() gets called in onCreate().
    private void loadFolders () {
        NotesFoldersJoinDAO notesFoldersJoinDao = NotesDB.getInstance(this).notesFoldersJoinDAO();
        List<Folder> folderList = folderDao.getAllFolders();
        List<Folder> checkedFolderList = notesFoldersJoinDao.getFoldersFromNote(note.getId());
        ArrayList<Folder> folders = new ArrayList<>(folderList);
        
        //The code gets called here.
        checkAlreadyCheckedFolders(checkedFolderList, folderList);
        
        this.foldersAdapter = new FoldersAddToFoldersAdapter(folders, checkedFolderList, note, this, folderDao, notesFoldersJoinDao);
        this.foldersListRv.setAdapter(foldersAdapter);
    }

    //The code moved to here, with a bit of modification and gets called in loadFolders().
    private void checkAlreadyCheckedFolders(List<Folder> checkedFolderList, List<Folder> folderList) {
        for (Folder checkedFolder : checkedFolderList) {
            for (Folder folder : folderList) {
                if (checkedFolder.getId() == folder.getId()) {
                    folder.setChecked(true);
                }
            }
        }
    }

Finally the “Folder” Room db Entity(table):

@Entity(tableName = "folders")
public class Folder {
    @ColumnInfo(name = "folderId")
    @PrimaryKey
    private int id;

    @ColumnInfo(name = "folderName")
    private String folderName;

    //The checked state gets saved as a room db column, in each folder.
    private boolean checked;

    public Folder() {
    }

    public String getFolderName() {
        return folderName;
    }

    public void setFolderName(String folderName) {
        this.folderName = folderName;
    }
    
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    //From this method, it gets and returns the checked state of the checkbox.
    public boolean isChecked() {
        return checked;
    }

    //And from this method, it sets the checked state of the checkbox.
    public void setChecked(boolean checked) {
        this.checked = checked;
    }
}

That way the checkbox checking runs only once when Activity(AddToFoldersActivity) starts/gets created and not again and again, in each scroll, inside onBindViewHolder(). onBindViewHolder() runs on each scroll.

Advertisement