2

I'm using room persistence library to update the database. I'm stuck at a point where I want to fetch the id of recently inserted record.

I know that using long as the return type for the insert method returns the id. But I access this Dao method through a viewmodel.

My DAO method is as follows:

//MyDao
@Insert
long insert(RecordItem record);

This method is accessed from a repository by doing this:

//MyRepository
public class MyRepository {
    private MyDao myDao;

    public MyRepository(@NonNull Application application) {
        MainDatabase mainDatabase = MainDatabase.getInstance(application);
        myDao = mainDatabase.myDao();
    }

    public void insert(RecordItem record) {
        MainDatabase.dbWriteExecutor.execute(() -> {
            myDao.insert(record);
        });
    }
}

And the repository method is called from viewmodel as follows:

//MyViewModel
public void insert(RecordItem record) {
    repository.insert(record);
}

And finally the viewmodel method as:

//MyActivity
myViewModel.insert(record);

My problem is, I don't know how I can get long returned through a viewmodel method. I tried doing this in repository

//MyRepository
public class MyRepository {
    private MyDao myDao;
    private long id;

    public MyRepository(@NonNull Application application) {
        MainDatabase mainDatabase = MainDatabase.getInstance(application);
        myDao = mainDatabase.myDao();
    }

    public long insert(RecordItem record) {
        MainDatabase.dbWriteExecutor.execute(() -> {
            id = myDao.insert(record);
        });
        return id;
    }
}

and subsequent changes to viewmodel method as well.

However, it returns 0, which I suppose happens since the insert method is executed on a different thread and id is returned as soon as the statement is reached(correct me if I'm wrong).

Thanks in advance.

dkhost07
  • 312
  • 1
  • 4
  • 17
  • You can try it by using callback interface way. Pass a single method interface as method parameter to repository method insert and invoke it on execute method to provide callback. – Jeel Vankhede May 25 '20 at 15:30
  • @JeelVankhede can you explain how to do it the way you suggest? – dkhost07 May 25 '20 at 15:42
  • An example of using `Callable` to perform background work and return a result is given in [this answer](https://stackoverflow.com/a/58767934/4815718). – Bob Snyder May 25 '20 at 19:00

2 Answers2

1

You can approach following solution for your issue:

Create a Callback interface as below:

public interface DbInsertCallback {
    void onInsert(long insertedItemId);
}

Then use this interface on your repository insert(RecordItem record) method like below usage:

public class MyRepository {
    
    // ... Some repo code ...

    public void insert(RecordItem record, DbInsertCallback callback) {
        MainDatabase.dbWriteExecutor.execute(() -> {
            long id = myDao.insert(record);
            callback.onInsert(id);
        });
    }

    // ... Rest of repo code ...
}

And also make necessary changes on caller site (I.e. ViewModel & Activity) to provide object of this callback class as parameter as well. To do the implementation of this interface, you can either create object of that interface along with implementation or else pass it contextually like providing this.

Jeel Vankhede
  • 11,592
  • 2
  • 28
  • 58
  • The Insert in the Dao returns a long and the DbInsertCalback interface you show uses a long. So in MyRepository, shouldn't the "int id = myDao.insert(record)" be set up as a long as well? So "long id = myDao.insert(record);"? – AJW Mar 28 '21 at 15:31
  • @AJW that's a good catch, thanks for the heads-up. I've edited the answer. Missed typo there. Also in the future, I'll suggest you to edit answer on any post if you've that privilege else you can also request for the change. – Jeel Vankhede Mar 28 '21 at 21:46
1

You can also use RxJava for this problem, where the insert method will return Single<Long>.

@Insert
Single<long> insert(RecordItem item)

Then when calling insert you call subscribe to get the returning id or use flatMap for any further actions using RxJava.

myDao.insert(record).subscribeWith(new DisposableSingleObserver<long>() {

    @Override
    public void onSuccess(long id) {
        // handle the id
    }

    @Override
    public void onError(Throwable e) {
        // handle the error case
    }
}

I suggest you to take a look at RxJava further down the line since it makes asynchronous programming much more natural and easier to work with and Room also implements it out of the box.

AndrejH
  • 2,028
  • 1
  • 11
  • 23