gig6
gig6

Reputation: 337

Android Room database @Insert method returns row id starting at 0

I have implemented the MVVM architecture in my app. I have my activity, viewmodel, repository, DAO, and database classes. The database holds objects that contain different lists that I want to switch between and have my RecyclerView show the currently selected list. My understanding is that row IDs in SQLite start at 1, but the insert method in my repository (which calls the @Insert method in my DAO) always starts with a row ID of 0. For testing purposes, I'm using LiveData to get all the objects in the database and when I log their IDs, they properly begin with 1 and go all the way to n. I don't want to maintain a list of all the objects in the database in memory, only the single object that contains the currently selected list. When a user creates a new list (or selects an existing list), I want to have my RecyclerView display its contents and observe any changes to that list. I can't start observing an object without its proper corresponding ID.

How do I propagate the proper ID to MainActivity? If my ViewModel and Activity code are needed please tell me and I will edit the post.

When I log the ID from the Repository

enter image description here

When I log the LiveData in MainActivity the proper IDs show

enter image description here

My Database class

@TypeConverters({ArrayListConverter.class}) // List converter for database
@Database(entities = ListContainer.class, version = 1, exportSchema = false)
public abstract class ListContainerDatabase extends RoomDatabase {

  private static ListContainerDatabase dbInstance;
  private static final String DB_NAME = "list_container_db";
  private static final int NUM_THREADS = 4;

  final static ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);

  public abstract ListContainerDao getDao();

  public static synchronized ListContainerDatabase getInstance(Context context) {
    if(dbInstance == null) {
      dbInstance = Room.databaseBuilder(
              context.getApplicationContext(),
              ListContainerDatabase.class, DB_NAME)
              .fallbackToDestructiveMigration()
              .build();
    }
    return dbInstance;
  }

  public static Executor getExecutor() {
    return executor;
}

My DAO

@Dao
public interface ListContainerDao {

  @Insert
  long insertListContainer(ListContainer container);

... // other database queries

}

My Repository

public class Repository {

  private static final String TAG = "Repository";

  private ListContainerDao listContainerDao;
  private long id;

  private Executor executor = ListContainerDatabase.getExecutor();

  public Repository(Application application) {
    ListContainerDatabase containerDb = ListContainerDatabase.getInstance(application);
    listContainerDao = containerDb.getDao();
  }

  public long insertListContainer(ListContainer container) {
    executor.execute(new Runnable() {
      @Override
      public void run() {
        id = listContainerDao.insertListContainer(container);  // this returns ID starting at 0
      }
    });
    Log.i(TAG, "insertListContainer: from Repository id is :" + id);
    return id;
  }
}

Upvotes: 0

Views: 1538

Answers (1)

sergiy tykhonov
sergiy tykhonov

Reputation: 5103

You should consider the asynchronity of your code here:

private long id;

public long insertListContainer(ListContainer container) {
    // Timestamp #1. This started, first time id is not initialised, equals to 0
    executor.execute(new Runnable() { 
    @Override
      public void run() {
        id = listContainerDao.insertListContainer(container);  
        // Timestamp #3. This returns you id = 1, but with some delay, so this value changed id and will be returned only next time you call the method 
      }
    });
    // Timestamp #2. Main thread isn't blocked, so it doesn't wait for runnable to be executed as well and returns first time id = 0, next time - changed value - 1, and so on
    Log.i(TAG, "insertListContainer: from Repository id is :" + id); 
    return id;
  }

If you want to get result of asynchronous operation in Java you can use:

Upvotes: 1

Related Questions