简体   繁体   English

重新启动应用程序时房间数据库为空(相同的数据库名称)

[英]Room Database Empty when Restarted App ( Same DB Name)

I am newbie to the Android X Room Database.我是 Android X Room 数据库的新手。 Earlier I used Sqlitehelper class to access the sqlite databases and then migrated to room.之前我用Sqlitehelper class访问sqlite的数据库,然后迁移到room。 The question is, when I insert data into Room database table it stores for that moment and when I restart the app the data is gone.问题是,当我将数据插入 Room 数据库表时,它会在那一刻存储,而当我重新启动应用程序时,数据就会消失。 I want to have multiple tables in a single database.我想在一个数据库中有多个表。

DAO:道:

@androidx.room.Dao
public interface ItineraryDao {


@Insert(onConflict = OnConflictStrategy.IGNORE)
void insert(ItineraryData model);

@Update
void update(ItineraryData model);

@Delete
void delete(ItineraryData model);

@Query("DELETE FROM "+ CONSTANTS.ITINERARY_TABLE)
void deleteAllItinerary();

@Query("SELECT * FROM "+CONSTANTS.ITINERARY_TABLE+" ORDER BY Date ASC")
LiveData<List<ItineraryData>> getAllItinerary();

Database:数据库:

@Database(entities = {ItineraryData.class},version = 1,exportSchema = false)
public abstract  class ItineraryDatabase extends RoomDatabase {

private static ItineraryDatabase instance;
public abstract ItineraryDao Dao();

public static synchronized ItineraryDatabase getInstance(Context mCon){
    if (instance == null) {
        instance =
              Room.databaseBuilder(mCon.getApplicationContext(),
                                ItineraryDatabase.class, CONSTANTS.ITINERARY_TABLE)
                        .fallbackToDestructiveMigration()
                        .addCallback(roomCallback)
                        .build();
    }
  
    return instance;

}

private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
    @Override
    public void onCreate(@NonNull SupportSQLiteDatabase db) {
        super.onCreate(db);
  
        new PopulateDbAsyncTask(instance).execute();
    }
};
private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void> {
    PopulateDbAsyncTask(ItineraryDatabase instance) {
        ItineraryDao dao = instance.Dao();
    }
    @Override
    protected Void doInBackground(Void... voids) {
        return null;
    }

The above is the code I used is every table to generate table with different Dao's.上面是我使用的代码是每个表用不同的 Dao 生成表。 As I need to create the tablets in a single database i used same CONSTANTS.ITINERARY_TABLE for all of them.因为我需要在单个数据库中创建平板电脑,所以我对所有平板电脑都使用了相同的 CONSTANTS.ITINERARY_TABLE。 If I use differnt names in CONSTANTS.ITINERARY_TABLE this works fine.如果我在 CONSTANTS.ITINERARY_TABLE 中使用不同的名称,则效果很好。 But it creates different databases.但它会创建不同的数据库。

How can I create multiple tables in a single database without loosing data on restart.如何在单个数据库中创建多个表而不会在重新启动时丢失数据。 I went thorugh some earlier posts.我浏览了一些较早的帖子。 But they suggest to use different database names.但他们建议使用不同的数据库名称。

Thank you谢谢

How can I create multiple tables in a single database without loosing data on restart.如何在单个数据库中创建多个表而不会在重新启动时丢失数据。

You define multiple tables by specifying multiple @Entity annotated classes in the entities parameter of the @Database annotation.您可以通过在@Database注释的entities 参数中指定多个@Entity注释的类来定义多个表。

That is how you tell Room what tables will be created.这就是您告诉 Room 将创建哪些表的方式。

Where you use ItineraryDatabase.class, CONSTANTS.ITINERARY_TABLE , this is telling Room that the database (ie the file name) will be named as per CONSTANTS.ITINERARY_TABLE .在您使用ItineraryDatabase.class, CONSTANTS.ITINERARY_TABLE的地方,这告诉 Room 数据库(即文件名)将按照CONSTANTS.ITINERARY_TABLE命名。

I suspect that you want the same table layout/schema but multiple tables (possibly itself not a good idea as each table has overheads when a single column could indicate the equivalent of the row belonging to a specific set of data).我怀疑您想要相同的表布局/架构但需要多个表(这本身可能不是一个好主意,因为当单个列可以指示属于特定数据集的行的等效项时,每个表都有开销)。

  • you may wish to edit your question to say more about what you are trying to achieve and you may therefore get more elaborate and specific answers.您可能希望编辑您的问题以更多地说明您想要实现的目标,因此您可能会得到更详尽和具体的答案。 If you do then feel free to notify myself by comment as such to this answer.如果您这样做,请随时通过对此答案发表评论来通知我自己。 At the minimum I would then look at any changes, but there is a very good chance that I would elaborate.至少我会查看任何更改,但很有可能我会详细说明。

Additional (DEMO)附加(演示)

Considering the comment:-考虑评论:-

I want to have different table with different table schema's in a single database file.我想在单个数据库文件中使用不同表模式的不同表。 I have seperate entity classes for them.我为他们准备了单独的实体类。 Do i need to have getinstance for each table in this single class ( which extends with roomdatabase)?我是否需要为这个单一的 class 中的每个表设置 getinstance(随 roomdatabase 扩展)? One Database Class with multiple getinstance?具有多个 getinstance 的一个数据库 Class?

and also the presumption of a single schema (not that it matters much if not, simpler if not).以及单一模式的假设(并不是说如果没有就很重要,如果没有就更简单)。 Then consider the following code that is based very much on your code.然后考虑以下非常基于您的代码的代码。

ItineraryData (used as a model for two tables, so not @Entity annotated - can be ignored if different schemas);- ItineraryData (用作两个表的 model,因此没有 @Entity 注释 - 如果模式不同,可以忽略);-

class ItineraryData {
   @PrimaryKey
   Long id=null;
   long date=System.currentTimeMillis() / 1000;
   @NonNull
   String otherColumn;
}

CONSTANTS :-常量:-

class CONSTANTS {
   static final String ITINERARY_TABLE = "it01";
   static final String ITINERARY_TABLE_2 = "it02";
}

ItineraryTable01 (bit of a cheat as schema grabbed from ItineraryData):- ItineraryTable01 (从 ItineraryData 抓取的模式有点作弊):-

@Entity(tableName = CONSTANTS.ITINERARY_TABLE)
class ItineraryTable01 extends ItineraryData {
}

ItineraryTable02 (cheat again):- ItineraryTable02 (再次作弊):-

@Entity(tableName = CONSTANTS.ITINERARY_TABLE_2)
class ItineraryTable02 extends ItineraryData {
}

ItineraryDao ItineraryDao

@Dao
public interface ItineraryDao {
   
   @Insert(onConflict = OnConflictStrategy.IGNORE)
   void insert(ItineraryTable01 model);
   @Insert(onConflict = OnConflictStrategy.IGNORE)
   void insert(ItineraryTable02 model);

   @Update
   void update(ItineraryTable01 model);
   @Update
   void update(ItineraryTable02 model);

   @Delete
   void delete(ItineraryTable01 model);
   @Delete
   void delete(ItineraryTable02 model);

   @Query("DELETE FROM " + CONSTANTS.ITINERARY_TABLE)
   void deleteAllItineraryTable01();
   @Query("DELETE FROM " + CONSTANTS.ITINERARY_TABLE_2)
   void deleteAllItineraryTable02();

   @Query("SELECT * FROM " + CONSTANTS.ITINERARY_TABLE + " ORDER BY Date ASC")
   /*LiveData<*/List<ItineraryTable01>/*>*/ getAllItineraryTable01();
   @Query("SELECT * FROM " + CONSTANTS.ITINERARY_TABLE + " ORDER BY Date ASC")
      /*LiveData<*/List<ItineraryTable02>/*>*/ getAllItineraryTable02();
}
  • commented out LiveData so can run on MainThread (although queries not used in demo, but just in case)注释掉 LiveData,以便可以在 MainThread 上运行(尽管在演示中未使用查询,但以防万一)
  • note the close duplications for each table.注意每个表的紧密重复。

ItineraryDatabase行程数据库

@Database(entities = { ItineraryTable01.class,ItineraryTable02.class/*ItineraryData.class*/} ,version = 1,exportSchema = false)
public abstract  class ItineraryDatabase extends RoomDatabase {

   private static ItineraryDatabase instance;

   public abstract ItineraryDao Dao();

   public static synchronized ItineraryDatabase getInstance(Context mCon) {
      if (instance == null) {
         instance =
                 Room.databaseBuilder(mCon.getApplicationContext(),
                                 ItineraryDatabase.class, CONSTANTS.ITINERARY_TABLE)
                         .allowMainThreadQueries() /*<<<<<<<<<< Added for convenience brevity of demo */
                         .fallbackToDestructiveMigration()
                         .addCallback(roomCallback)
                         .build();
      }
      return instance;

   }

   private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
      @Override
      public void onCreate(@NonNull SupportSQLiteDatabase db) {
         super.onCreate(db);

         new PopulateDbAsyncTask(instance).execute();
      }
   };

   private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void> {
      PopulateDbAsyncTask(ItineraryDatabase instance) {
         ItineraryDao dao = instance.Dao();
      }

      @Override
      protected Void doInBackground(Void... voids) {
         return null;
      }
   }
}
  • allow to run on Main thread, otherwise unchanged (no need for callback though, it does nothing)允许在主线程上运行,否则不变(虽然不需要回调,但它什么都不做)

Finally to demo some code in an activity:-最后在活动中演示一些代码:-

public class MainActivity extends AppCompatActivity {

    ItineraryDatabase db;
    ItineraryDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ItineraryTable01 it01 = new ItineraryTable01();
        ItineraryTable02 it02 = new ItineraryTable02();

        it01.otherColumn = "blah01";
        it02.otherColumn = "blah02";

        db = ItineraryDatabase.getInstance(this);
        dao = db.Dao();
        /* Not until following code is executed is the database actually opened */
        dao.insert(it01); /* Inserts into table01 */
        dao.insert(it02); /* Inserts into table02 */

    }
}

Results结果

When first run第一次运行时

Using App Inspection:-使用应用检查:-

在此处输入图像描述

and

在此处输入图像描述

Run again (aka rerun)再次运行(又名重新运行)

在此处输入图像描述

and

在此处输入图像描述

  • as can be seen the data (rows highlighted) from the first run has been retained and data from the second run has been added (different generated id's and timestamps)可以看出,保留了第一次运行的数据(突出显示的行)并添加了第二次运行的数据(生成的不同 ID 和时间戳)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM