TransWikia.com

Viewmodel doesn't update data from Android Room, but successfully insert in it

Stack Overflow Asked by GremlinShX on February 10, 2021

I try to understand the Room persistence library with this course, however, I stuck with updating RecyclerView and populate it with data in Room. Sorry for this boilerplate code.
Data passing to Room successfully and kept there as Android Database Inspector show to me, but at the same time, Rycyclerview is empty. Here is my code :
Item:

@Entity (tableName = "active_accounts")
public class Dashboard_Account {

    @PrimaryKey (autoGenerate = true)
    int accountID;

    @ColumnInfo(name = "accountName")
     String accountName;

    @ColumnInfo(name = "accountEmail")
     String accountEmail;

    public Dashboard_Account() {

    }

    public Dashboard_Account(String accountName,String accountEmail) {
        this.accountName = accountName;
        this. accountEmail = accountEmail;
    }

//getters and setters

DAO

@Dao
public interface Dashboard_DAO {

    @Insert (onConflict = OnConflictStrategy.REPLACE)
    void insert(Dashboard_Account... dashboard_accounts);

    @Delete
     void delete(Dashboard_Account account);

    @Query("DELETE FROM active_accounts")
     void deleteAll();

    @Update
     void update(Dashboard_Account account);

    @Query("SELECT * FROM active_accounts" )
    LiveData<List<Dashboard_Account>> getAllAccounts();
}

Database

@Database(entities = {Dashboard_Account.class},version = 2,exportSchema = false)
public abstract class Dashboard_Database extends RoomDatabase {
        public abstract Dashboard_DAO dashboard_dao();

        private static Dashboard_Database INSTANCE;

        public static Dashboard_Database getDatabase(final Context context) {
                if (INSTANCE == null) {
                        synchronized (Dashboard_Database.class) {
                                if (INSTANCE == null) {
                                        INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                                                Dashboard_Database.class, "account_database")
                                                .fallbackToDestructiveMigration()
                                                .build();
                                }
                        }
                }
                return INSTANCE;
        }
}

Repository class

public class Dashboard_Repository {
    private Dashboard_DAO mDashboardDao;
    private LiveData<List<Dashboard_Account>> mAllAccounts;

    Dashboard_Repository(Application application) {
        Dashboard_Database db = Dashboard_Database.getDatabase(application);
        mDashboardDao = db.dashboard_dao();
        mAllAccounts = mDashboardDao.getAllAccounts();
    }

    LiveData<List<Dashboard_Account>> getAllAcounts(){
        return mAllAccounts;
    }

    public void insert (Dashboard_Account account) {
        new insertAsyncTask(mDashboardDao).execute(account);
    }

    private static class insertAsyncTask extends AsyncTask<Dashboard_Account, Void, Void> {

        private Dashboard_DAO mAsyncTaskDao;

        insertAsyncTask(Dashboard_DAO mDashboardDao) {
            mAsyncTaskDao = mDashboardDao;
        }

        @Override
        protected Void doInBackground(final Dashboard_Account... params) {
            mAsyncTaskDao.insert(params[0]);
            return null;
        }
    }

Viewmodel

public class Dashboard_ViewModel extends AndroidViewModel {
    private Dashboard_Repository mRepo;
    private LiveData<List<Dashboard_Account>> mAllAccounts;


    public Dashboard_ViewModel(@NonNull Application application) {
        super(application);
        mRepo = new Dashboard_Repository(application);
        mAllAccounts = mRepo.getAllAcounts();
    }

    LiveData<List<Dashboard_Account>> getmAllAccounts() { return mAllAccounts; }
    public void insert(Dashboard_Account account) { mRepo.insert(account); }
}

For adding data I use DialogFragment with setFragmentResultListener that placed in Fragment onViewCreated()

public class Dashboard_Fragment extends Fragment {
…
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
setRecyclerView();
getParentFragmentManager().setFragmentResultListener("fragmentKey", getViewLifecycleOwner(), (requestKey, result) -> {
       String name = result.getString("nameResult");
       String email = result.getString ("email");

       Dashboard_Account account = new Dashboard_Account(name,email);
       dashboardViewModel.insert(account);
});
}

And the code of recyclerview setup:

private void setRecyclerView(){
    binding.accountView.setLayoutManager(new LinearLayoutManager(requireContext()));
    adapter = new Dashboard_RecyclevrViewAdapter(AccountItemList);
    dashboardViewModel.getmAllAccounts().observe(requireActivity(), accounts -> {
        adapter.setListContent(AccountItemList);
    });
    binding.accountView.setAdapter(adapter);
}

RecyclerViewAdapter is typical and here onBindViewHolder and setListcontent:

public class Dashboard_RecyclevrViewAdapter extends RecyclerView.Adapter<Dashboard_RecyclevrViewAdapter.MyViewHolder>  {
....
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
    if(pad_list!=null){
        final Dashboard_Account account  = pad_list.get(position);
        
        holder.binding.accountType.setText(account.getAccountName());
        holder.binding.acountemail.setText(account.getAccountValue()));
    }

}
…
public void setListContent(List <Dashboard_Account> pad_list) {
    this.pad_list = pad_list;
    notifyItemChanged(getItemCount());
}
….
}

I am really can’t understand why the recycler view doesn’t show data after I add the item to ViewModel, that in theory should handle with that. I will provide additional code if it will be needed. Thanks in advance.

2 Answers

Besides notifyDataSetChanged() that pointed out by @a_local_nobody you need to send the updated list to the RecyclerView adapter, not the original list

To do that replace dapter.setListContent(AccountItemList); with dapter.setListContent(accounts); in setRecyclerView()

private void setRecyclerView(){
    binding.accountView.setLayoutManager(new LinearLayoutManager(requireContext()));
    adapter = new Dashboard_RecyclevrViewAdapter(AccountItemList);
    dashboardViewModel.getmAllAccounts().observe(requireActivity(), accounts -> {
        adapter.setListContent(accounts); // <<< Change here
    });
    binding.accountView.setAdapter(adapter);
}

Answered by Zain on February 10, 2021

public void setListContent(List <Dashboard_Account> pad_list) {
    this.pad_list = pad_list;
    notifyItemChanged(getItemCount());
}

could be wrong but i don't really see the point of doing notifyItemChanged here, try adding in notifyDataSetChanged() instead


notifyItemChanged tells the recycler that a specific item has been changed, while notifyDataSetChanged informs the recycler that all the data has (potentially) changed, this forces it to rebind all the items it has.

From the course you've mentioned, there's no reference to notifyItemChanged, so i'm not sure why you added it :)

the course link you've provided has:

void setWords(List<Word> words){
       mWords = words;
       notifyDataSetChanged(); <-- notifyDataSetChanged, not itemChanged
   }

Answered by a_local_nobody on February 10, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP