本文介绍了Android Room 数据库@Insert 方法返回从 0 开始的行 ID的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在我的应用中实现了 MVVM 架构.我有我的活动、视图模型、存储库、DAO 和数据库类.数据库包含包含不同列表的对象,我想在这些列表之间切换,并让我的 RecyclerView 显示当前选择的列表.我的理解是 SQLite 中的行 ID 从 1 开始,但我的存储库中的 insert 方法(在我的 DAO 中调用 @Insert 方法)始终以行 ID 0 开头.出于测试目的,我使用 LiveData 来获取数据库中的所有对象以及当我记录它们的 ID 时,它们正确地从 1 开始一直到 n.我不想在内存中维护数据库中所有对象的列表,只维护包含当前选定列表的单个对象.当用户创建新列表(或选择现有列表)时,我希望我的 RecyclerView 显示其内容并观察对该列表的任何更改.如果没有正确的对应 ID,我无法开始观察对象.

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.

如何将正确的 ID 传播到 MainActivity?如果需要我的 ViewModel 和 Activity 代码,请告诉我,我会编辑帖子.

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.

当我从存储库中记录 ID 时

When I log the ID from the Repository

当我在 MainActivity 中记录 LiveData 时,会显示正确的 ID

When I log the LiveData in MainActivity the proper IDs show

我的数据库类

@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;
}

我的 DAO

@Dao
public interface ListContainerDao {

  @Insert
  long insertListContainer(ListContainer container);

... // other database queries

}

我的仓库

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;
  }
}

推荐答案

您应该在这里考虑代码的异步性:

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;
  }

如果你想在Java中获得异步操作的结果,你可以使用:

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

这篇关于Android Room 数据库@Insert 方法返回从 0 开始的行 ID的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 18:50