0

I created a room database following this guide from code labs It makes use of a repository to:

A Repository manages query threads and allows you to use multiple backends. In the most common example, the Repository implements the logic for deciding whether to fetch data from a network or use results cached in a local database.

I followed the guide and i'm now able to create the entity's & retrieve the data. I even went further and created another whole entity outside the scope of the guide.

However I can't find many resources that use this MVVM(?) style so am struggling as to really under stand the repository. For now I want to update a field. Just one, as if I am able to manage that the rest should be similar.

I want to update a field called dartshit and I have the dao method created for this:

@Query("UPDATE AtcUserStats SET dartsHit = :amount WHERE userName = :userName") void UpdateHitAmount(int amount, String userName);

I have one repository which I assumed I use for all entities:

public class UsersRepository {

private UsersDao mUsersDao;
private AtcDao mAtcDao;
private LiveData<List<Users>> mAllUsers;
private LiveData<List<AtcUserStats>> mAllAtc;
private AtcUserStats mAtcUser;

UsersRepository(Application application) {
    AppDatabase db = AppDatabase.getDatabase(application);
    mUsersDao = db.usersDao();
    mAtcDao = db.atcDao();
    mAllUsers = mUsersDao.fetchAllUsers();
    mAllAtc = mAtcDao.getAllAtcStats();
}

LiveData<List<Users>> getAllUsers() {
    return mAllUsers;
}

LiveData<List<AtcUserStats>> getAllAtcStats() {
    return mAllAtc;
}

LiveData<AtcUserStats> getAtcUser(String username) {

    return mAtcDao.findByName(username);
}

public void insert (Users user) {
    new insertAsyncTask(mUsersDao).execute(user);
}

public void insertAtc (AtcUserStats atc) {
    new insertAsyncAtcTask(mAtcDao).execute(atc);
}

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

    private UsersDao mAsyncTaskDao;

    insertAsyncTask(UsersDao dao) {
        mAsyncTaskDao = dao;
    }

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

private static class insertAsyncAtcTask extends AsyncTask<AtcUserStats, Void, Void> {

    private AtcDao mAsyncTaskDao;

    insertAsyncAtcTask(AtcDao dao) {
        mAsyncTaskDao = dao;
    }

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

My question is how do I create a AsyncTask for the update query I am trying to run in this repository?

Here is what I have so far by broadly copying the insert repository methods:

private class updateHitAsyncTask {

    private AtcDao mAsyncTaskDao;

    public updateHitAsyncTask(AtcDao mAtcDao) {

        mAsyncTaskDao = mAtcDao;
    }

    protected Void doInBackground(int amount, String name) {
        mAsyncTaskDao.UpdateHitAmount(amount, name);
        return null;
    }
}

Which is incorrect is that I'm getting a llegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time. error. But i thought this AsyncTask is suppose to take care of this?

Here is my update method in my view model, which is reporting 0 errors:

  void updateHitAmount (int amount, String name) {
    mRepository.updateAtcHits(amount, name);
}

and here is the UI code where im actually trying to tie all these together, I suspect there must be a better way that using onChanged for simply updating a field but again I am struggling to come across any advice on google with the repository approach:

   private void callOnChanged() {

    mAtcViewModel = ViewModelProviders.of(this).get(AtcViewModel.class);

    mAtcViewModel.getAllUsers().observe(this, new Observer<List<AtcUserStats>>() {
        @Override
        public void onChanged(@Nullable final List<AtcUserStats> atc) {
            // Update the cached copy of the users in the adapter.


            for (int i = 0; i < atc.size(); i++) {
                if (atc.get(i).getUserName().equals(mUser)) {
                    mAtcViewModel.updateHitAmount(55, mUser);
                    //atc.get(i).setDartsHit(55);
                    Log.d("id", String.valueOf(userSelected.getId()));
                }
            }
        }
    });

How can I update fields using this approach on the background thread?

COYG
  • 1,538
  • 1
  • 16
  • 31

1 Answers1

1

Figured it out due to this answer here. It was mostly because of my lack of understanding of AsyncTask. Essentially I needed to create an object and pass the data that way and then execute in the background:

 private static class MyTaskParams {
    int amount;
    String name;

    MyTaskParams(int amount, String name) {
        this.amount = amount;
        this.name = name;
    }
}

public void updateAtcHits (int amount, String name) {

    MyTaskParams params = new MyTaskParams(amount,name);
    new updateHitAsyncTask(mAtcDao).execute(params);
}

private class updateHitAsyncTask extends AsyncTask<MyTaskParams,Void,Void>{

    private AtcDao mAsyncTaskDao;

    public updateHitAsyncTask(AtcDao mAtcDao) {

        mAsyncTaskDao = mAtcDao;
    }

    @Override
    protected Void doInBackground(MyTaskParams... myTaskParams) {
        int amount =myTaskParams[0].amount;
        String name = myTaskParams[0].name;
        mAsyncTaskDao.UpdateHitAmount(amount, name);
        return null;
    }
}
COYG
  • 1,538
  • 1
  • 16
  • 31