Room数据库无法预填充数据,并且未创建数据库文件

问题描述 投票:1回答:1

我已经在Application中实现了Room数据库。我想在首次打开应用程序时预填充数据。 Entity类看起来像

@Entity(tableName = NameConstants.TABLE_NAME)
public class Name {

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = NameConstants.COL_NAME)
    private String Name;

    @ColumnInfo(name= NameConstants.COL_PHONE)
    private String Phone;

    @ColumnInfo(name = NameConstants.COL_CITY)
    private String City;

    public Name(){

    }

    public Name(String name, String phone, String city) {
        Name = name;
        Phone = phone;
        City = city;
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public String getPhone() {
        return Phone;
    }

    public void setPhone(String phone) {
        Phone = phone;
    }

    public String getCity() {
        return City;
    }

    public void setCity(String city) {
        City = city;
    }
}  

DAO实现是

@Dao
public interface NameDAO {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertAll(Name... names);

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert(Name name);

    @Delete
    void delete(Name name);
}  

Database类似乎是这样的,其中从一个Raw文件中读取数据

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

    public abstract NameDAO nameDAO();

    private static volatile  NameDatabase dInstance=null;

     static synchronized NameDatabase getInstance(final Context context){
        if(dInstance==null){
            synchronized (NameDatabase.class){
                if(dInstance==null){
                    dInstance= Room.databaseBuilder(context.getApplicationContext(),NameDatabase.class,"appdatabase")
                            .allowMainThreadQueries()
                            .addCallback(new Callback() {
                                @Override
                                public void onCreate(@NonNull SupportSQLiteDatabase db) {
                                    super.onCreate(db);
                                   fillWithDemoData(context);
                                }

                            }
                            ).build();
                }
            }
        }
        return dInstance;
    }

    @WorkerThread
    private static void fillWithDemoData(Context context){
        NameDAO dao=getInstance(context).nameDAO();
        JSONArray emoji = loadJsonArray(context);
        try {
            for (int i = 0; i < emoji.length(); i++) {
                JSONObject item = emoji.getJSONObject(i);
                dao.insert(new Name(item.getString("name"),
                        item.getString("phone"),
                        item.getString("city")));
            }
        } catch (JSONException exception) {
            exception.printStackTrace();
        }
    }
    private static JSONArray loadJsonArray(Context context) {
        StringBuilder builder = new StringBuilder();
        InputStream in = context.getResources().openRawResource(R.raw.namesdata);
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));

        String line;
        try {
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            JSONObject json = new JSONObject(builder.toString());
            return json.getJSONArray("names");

        } catch (IOException | JSONException exception) {
            exception.printStackTrace();
        }

        return null;
    }
}  

Repository类是公共的

class DataRepository {

    private NameDAO nDao;

    public DataRepository(Application application) {
        NameDatabase database = NameDatabase.getInstance(application);
        nDao = database.nameDAO();
    }
}  

安装应用程序并打开应用程序时,它不会崩溃,但不会创建任何数据库文件,也不会在数据库中插入任何数据。代码中还缺少什么或有什么错误?

android database android-room android-database
1个回答
1
投票

安装应用程序并打开应用程序时,它不会崩溃,但不会创建数据库文件,也不会在数据库中插入任何数据。

如果没有崩溃,那么我相信您对数据库没有做任何其他事情。只需构建它并获取实例。

除非您尝试访问数据库,否则不会创建数据库。您需要尝试对数据库执行某些操作。

但是!!!!

然后您将获得java.lang.IllegalStateException: getDatabase called recursively FATAL例外。

基本上是通过访问数据库,然后尝试打开它,因为该数据库不存在,将调用onCreate回调,然后通过插入来访问数据库的attemtp将尝试打开数据库,从而进行递归。

总之,您只能通过传递给onCreate的SupportSQLiteDatabase访问数据库。

您可以使用:-

public static void fillWithDemoData(Context context, SupportSQLiteDatabase sdb){

    ContentValues cv = new ContentValues(); //<<<<<<<<<< ADDED


    JSONArray emoji = loadJsonArray(context);
    try {
        for (int i = 0; i < emoji.length(); i++) {
            JSONObject item = emoji.getJSONObject(i);

            //<<<<<<<<<< CANNOT USE ROOM here >>>>>>>>>
            //dao.insert(new Name(item.getString("name"),
            //        item.getString("phone"),
            //        item.getString("city")));


            cv.clear();
            cv.put(NameConstants.COL_NAME,item.getString(NameConstants.COL_NAME));
            cv.put(NameConstants.COL_CITY,item.getString(NameConstants.COL_CITY));
            cv.put(NameConstants.COL_PHONE,item.getString(NameConstants.COL_PHONE));
            sdb.insert(NameConstants.TABLE_NAME, OnConflictStrategy.IGNORE,cv);
        }
    } catch (JSONException exception) {
        exception.printStackTrace();
    }

}

BUT您需要尝试访问ROOM,例如因此在您进行的活动或同等活动中,您可以使用:-

    ndb = NameDatabase.getInstance(this); //<<<<<<<<<< ROOM databse not yet created (opened)
    ndb.getOpenHelper(); //<<<<<<<<<< FORCE OPEN and thus create (or just access the db via a Dao call)

示例/演示/测试

由于我无权访问您的JSON文件,因此我已经使用:-]测试了上述内容。

@WorkerThread
public static void fillWithDemoData(Context context, SupportSQLiteDatabase sdb){

    ContentValues cv = new ContentValues(); //<<<<<<<<<< ADDED
    cv.clear();
    cv.put(NameConstants.COL_NAME,"Fred");
    cv.put(NameConstants.COL_CITY,"London");
    cv.put(NameConstants.COL_PHONE,"0000000000");
    sdb.insert(NameConstants.TABLE_NAME, OnConflictStrategy.IGNORE,cv);

    /*
    JSONArray emoji = loadJsonArray(context);
    try {
        for (int i = 0; i < emoji.length(); i++) {
            JSONObject item = emoji.getJSONObject(i);

            //<<<<<<<<<< CANNOT USE ROOM here >>>>>>>>>
            //dao.insert(new Name(item.getString("name"),
            //        item.getString("phone"),
            //        item.getString("city")));


            cv.clear();
            cv.put(NameConstants.COL_NAME,item.getString(NameConstants.COL_NAME));
            cv.put(NameConstants.COL_CITY,item.getString(NameConstants.COL_CITY));
            cv.put(NameConstants.COL_PHONE,item.getString(NameConstants.COL_PHONE));
            sdb.insert(NameConstants.TABLE_NAME, OnConflictStrategy.IGNORE,cv);
        }
    } catch (JSONException exception) {
        exception.printStackTrace();
    }
    */
}
  • 还注释了loadJsonArray]中的代码

    并且使用的活动是:-

public class MainActivity extends AppCompatActivity {

    NameDatabase ndb;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ndb = NameDatabase.getInstance(this);
        ndb.getOpenHelper(); //<<<<<<<<<< FORCE OPEN and thus create (not needed as db accessed below)

        //This would also do the same, this used to test the data//
        List<Name> nameList = ndb.nameDAO().getALl();
        for (Name n: nameList) {
            logName(n);
        }
    }

    private void logName(Name n) {
        Log.d("NAMEINFO","Name is " + n.getName() + "\n\tCity is " + n.getCity() + "\n\tPhone is " + n.getPhone() + "ID is " + n.getId());
    }
}

结果

安装后首次运行:-

2019-11-14 08:22:08.483 D/ONCREATE: onCreate has been called
2019-11-14 08:22:08.492 D/NAMEINFO: Name is Fred
      City is London
      Phone is 0000000000ID is 1
  • 未在onCreate中添加日志,因此它表明已被调用。

第二轮:-

2019-11-14 08:23:22.532 D/NAMEINFO: Name is Fred
      City is London
      Phone is 0000000000ID is 1
© www.soinside.com 2019 - 2024. All rights reserved.