9

I am working on Android Room Persistent library. I have also implemented Two-way data binding in my project. In the project, I am inserting users by filling a form and displaying all the users in rows and updating them by clicking particular user row. Below is my UserDao Class:

@Dao
public interface UserDao {

  @Query("SELECT * FROM user")
  List<User> getAllUsers();

  @Insert
  void insertAll(User... users);

  @Update
  void updateUser(User... users);

  @Query("SELECT * FROM user WHERE user_id IN (:userId)")
  User getSpecifiedUser(int...userId);
 }

For databinding I am binding User Model in UserFormActivity

binding.setUserModel(userModel);

Now, as Room persistent library doesn't allow you to do any database operation in Main thread, for updating the user, I am getting data of particular user in User Form by clicking in the row in new Thread as below:

 private void getUserFormData(final int userId) {
    try {
        Thread t = new Thread(new Runnable() {
            public void run() {
                userModel = db.userDao().getSpecifiedUser(userId);
            }
        }, "Thread A");
        t.start();
    } catch (NumberFormatException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

After getting data of user in userModel for updating, I want the User data to reflect in User Form where data binding is performed, but it's not reflecting. I am stuck with this issue.

Priyanka Alachiya
  • 1,707
  • 2
  • 20
  • 31
  • 1
    In which part of the Room documentation you read "Room persistent library doesn't allow you to do any database operation in Main thread" ? – MatPag May 29 '17 at 11:59
  • I don't understand one thing, if you set the binding before you load the object, how can it be updated? Shouldn't you call binding.setUserModel(userModel) after loading it from db? – lelloman May 29 '17 at 12:06
  • 2
    @MatPag: It is not documented, but Room will throw an exception if you try doing Room I/O on the main application thread. – CommonsWare May 29 '17 at 12:18
  • 1
    Use `LiveData`, or `AsyncTask`, or an event bus, or RxJava/RxAndroid, or something to do the query on the background thread, then arrange to update your UI on the main application thread. Room, in particular, is designed for use with `LiveData`, `ViewModel`, and the rest of the Architecture Components. – CommonsWare May 29 '17 at 12:19
  • @CommonsWare mmm that's really bad, thanks for the clarification – MatPag May 29 '17 at 12:19
  • @MatPag: To clarify, I have heard reports that Room does this, such as https://stackoverflow.com/q/44167111/115145. I haven't tried it personally because doing disk I/O on the main application thread is not a good plan. – CommonsWare May 29 '17 at 12:23
  • @CommonsWare thanks for clearing the Thread part. And I will definitely try LiveData and ViewModel concept, it seems to be promising. – Priyanka Alachiya May 29 '17 at 12:30
  • @lelloman Even if I set the binding method before loading the object, it does reflect in databinding. So that's not the issue here I guess. – Priyanka Alachiya May 29 '17 at 12:32
  • @CommonsWare following the codelabs [here](https://codelabs.developers.google.com/codelabs/android-persistence/#3) the warning at the end of the page let me think that the library should allows operations on the Main thread (even if it's highly discouraged). I will need to perform some more researches on the topic ;) – MatPag May 29 '17 at 12:34
  • 6
    It is documented and explained here: https://developer.android.com/reference/android/arch/persistence/room/RoomDatabase.Builder.html#allowMainThreadQueries(). – yigit May 29 '17 at 19:48

1 Answers1

10

I implemented LiveData and ViewModel in my project and also extended LifecycleActivity in my UserListActivity. Here is my AddUserViewModel class:

public class AddUserViewModel extends AndroidViewModel {
     private UserDatabase userDatabase;

     public AddUserViewModel(Application application) {
      super(application);

     userDatabase = UserDatabase.getDatabase(this.getApplication());
     }

     public void addUser(User user) {
     new AddUserAsyncTask(userDatabase).execute(user);
     }

     private static class AddUserAsyncTask extends AsyncTask<User, Void, 
        Void> {

        private UserDatabase db;

        public AddUserAsyncTask(UserDatabase userDatabase) {
             db = userDatabase;
        }

     @Override
     protected Void doInBackground(User... params) {
         db.userDao().insertUser(params);
         return null;
         }
     }

    public User getSpecificUserData(int userId) {
        User user = null;
        try {
             user = new 
             getUserDataAsyncTask(userDatabase).execute(userId).get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
           }
        return user;
    }

    private static class getUserDataAsyncTask extends AsyncTask<Integer, 
        Void, User> {

        private UserDatabase db;

        public getUserDataAsyncTask(UserDatabase userDatabase) {
            db = userDatabase;
        }

        @Override
        protected User doInBackground(Integer... userId) {
            User user = db.userDao().getSpecifiedUser(userId);
            return user;
        }

        @Override
        protected void onPostExecute(User user) {
            super.onPostExecute(user);
        }
      }
  }

In AddUserActivity I am getting particular User data from database method as

userModel = addUserViewModel.getSpecificUserData(userId);

and updating the data on click of submit button. My UserListActivity extends LifecycleActivity in which the user list gets observed and when ever change is there it updates the Use list as below:

 userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);

    userViewModel.getUserList().observe(UserListActivity.this, new 
    Observer<List<User>>() {
        @Override
        public void onChanged(@Nullable List<User> user) {
            adapter.addItems(user);
        }
    });

This worked fine for me and I got my solution!

Priyanka Alachiya
  • 1,707
  • 2
  • 20
  • 31