【问题标题】:How to force Room's OnCreate callback to work?如何强制 Room 的 OnCreate 回调工作?
【发布时间】:2020-06-06 20:13:17
【问题描述】:

我非常坚持这一点。我正在关注 Google 的“ArchitectureComponentsBasic1”,您可以通过转到 File -> New -> Import Sample 将其导入 Android Studio。我也遵循了 Maxim 在this SO 文章中提供的建议。什么都没有工作。如何让 OnCreate 回调运行,以便预填充我的数据库?

数据库:请注意,我正在我的 buildDatabase 方法中运行执行程序,以尝试运行一个虚拟查询以根据上面链接的 SO 运行 getWritableDatabase()。这不起作用。

        version = 1,
        exportSchema = false)
public abstract class ProjectDatabase extends RoomDatabase {
    private final MutableLiveData<Boolean> isDatabaseCreated = new MutableLiveData<>();
    private static ProjectDatabase instance;
    private static final String DATABASE_NAME = "project.db";
    private static final String TAG = ProjectDatabase.class.getSimpleName();

    public abstract ProjectDao projectDao();

    public static ProjectDatabase getInstance(final Context context, final AppExecutors appExecutors) {
        if (instance == null) {
            synchronized (ProjectDatabase.class) {
                if (instance == null) {
                    instance = buildDatabase(context.getApplicationContext(), appExecutors);
                    instance.updateDatabaseCreated(context.getApplicationContext());
                }
            }
        }
        return instance;
    }

    private static ProjectDatabase buildDatabase(final Context appContext, final AppExecutors appExecutors) {
        Log.d(TAG, "building database.");
        ProjectDatabase db = Room.databaseBuilder(appContext, ProjectDatabase.class, DATABASE_NAME)
                .addCallback(new Callback() {
                    @Override
                    public void onCreate(@NonNull SupportSQLiteDatabase db) {
                        super.onCreate(db);
                        Log.d(TAG, "callback was called.");
                        appExecutors.diskIO().execute(() -> {
                            ProjectDatabase database = ProjectDatabase.getInstance(appContext, appExecutors);
                            List<Project> projects = DataGenerator.generateProjects();

                            Log.d(TAG, "project data: " + projects.get(0).getTitle());

                            insertData(database, projects);
                            database.setDatabaseCreated();
                        });
                    }
                })
                .build();

        appExecutors.diskIO().execute(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "populate database");
                db.projectDao().populateDatabase();
            }
        });

        return db;
    }

    /**
     * Check whether the database already exists and expose it via {@link #getDatabaseCreated()}
     */
    private void updateDatabaseCreated(final Context context) {
        if (context.getDatabasePath(DATABASE_NAME).exists()) {
            setDatabaseCreated();
        }
    }

    private void setDatabaseCreated(){
        Log.d(TAG, "database created");
        isDatabaseCreated.postValue(true);
    }

    private static void insertData(final ProjectDatabase database, final List<Project> projects) {
        database.runInTransaction(() -> {
            database.projectDao().insertAll(projects);
        });
    }

DAO 项目

@Dao
public interface ProjectDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    void insertAll(List<Project> projects);

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    void insert(Project project);

    @Query("SELECT * FROM project")
    LiveData<List<Project>> loadAllProjects();

    @Query("SELECT * FROM project WHERE is_favorite = 1")
    LiveData<Project[]> getAllFavorites();

    @Query("SELECT is_favorite FROM project WHERE id = :projectId")
    int isFavorite(int projectId);

    @Query("UPDATE project SET is_favorite = 1 WHERE id = :projectId")
    int addToFavorites(int projectId);

    @Query("UPDATE project SET is_favorite = 0 WHERE id = :projectId")
    int removeFromFavorites(int projectId);


    // Dummy query needed to activate the Room callback method to prepopulate the database
    @Query("SELECT * from project")
    LiveData<Project> populateDatabase();
}

【问题讨论】:

  • 您好,我可以理解您的Callback() 在您第一次打开应用程序时没有在您的数据库上调用?
  • @Zain 是的,回调没有被调用。根据我的阅读,在您对数据库执行第一个操作之前,不会调用 onCreate 回调。这就是我添加 db.projectDao.populateDatabase 的原因,它旨在对虚拟数据进行数据库操作。但即使它被调用,onCreate 回调仍然没有被调用。
  • 返回数据库实例后能否尝试从ViewModel调用updateDatabaseCreated()
  • 这与问题没有任何关系。问题是 onCreate 回调没有被调用。
  • 你不想使用out-of-box way for prepopulating in Room吗?我猜你提到的文章和例子有点过时了。这些更改是在 October 2019 的 Room 中进行的。

标签: android android-room android-architecture-components


【解决方案1】:

您需要为任何返回 LiveData 的 dao 方法注册至少一个观察者。当观察者注册时,您的 roomCallback onCreate 将被调用。

要删除那些嵌套的意大利面条代码,您可以使用 AsyncTask 预填充 db,所以它看起来像这样:

public static synchronized ProjectDatabase getInstance(Context context) {
    if (instance == null) {
        instance = Room.databaseBuilder(context.getApplicationContext(),
                ProjectDatabase.class, DATABASE_NAME)
                .addCallback(roomCallback)
                .build();
    }
    return instance;
    }

 private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
    @Override
    public void onCreate(@NonNull SupportSQLiteDatabase db) {
        super.onCreate(db);
        Log.d(TAG, "callback was called.");
        new PopulateDbAsyncTask(instance).execute();
    }
};

private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void>
{
    private ProjectDao projectDao;
    private PopulateDbAsyncTask(ProjectDatabase db){
        projectDao=db.projectDao();
    }
    @Override
    protected Void doInBackground(Void... voids) {
        List<Project> projects = DataGenerator.generateProjects();
        projectDao.insertAll(projects )
        return null;
    }
}

}

【讨论】:

    猜你喜欢
    • 2018-06-25
    • 2013-02-14
    • 1970-01-01
    • 1970-01-01
    • 2016-11-04
    • 2015-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多