Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
附带预填充数据库的android应用程序_Android_Sqlite - Fatal编程技术网

附带预填充数据库的android应用程序

附带预填充数据库的android应用程序,android,sqlite,Android,Sqlite,这是我的密码 public DBHelper(Context context) { super(context, DB_NAME, null, 2); this.context = context; DB_PATH = context.getDatabasePath(DB_NAME).getAbsolutePath(); } @Override public void onCreate(SQLiteDatabase db) { createDataBase();

这是我的密码

public DBHelper(Context context) {
    super(context, DB_NAME, null, 2);
    this.context = context;
    DB_PATH = context.getDatabasePath(DB_NAME).getAbsolutePath();
}

@Override
public void onCreate(SQLiteDatabase db) {
    createDataBase();
}

private void createDataBase() {
    boolean dbExist = checkDataBase();
    if (!dbExist) {
        copyDataBase();
    }
}

private boolean checkDataBase() {
    System.out.println("DB_PATH : " + DB_PATH);
    File dbFile = new File(DB_PATH);
    return dbFile.exists();
}

private void copyDataBase() {
    Log.i("Database",
            "New database is being copied to device!");
    byte[] buffer = new byte[1024];
    OutputStream myOutput;
    int length;
    InputStream myInput;
    try {
        myInput = context.getAssets().open(DB_NAME);
        myOutput = new FileOutputStream(DB_PATH);
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }
        myOutput.close();
        myOutput.flush();
        myInput.close();
        Log.i("Database",
                "New database has been copied to device!");
    } catch (IOException e) {
        e.printStackTrace();
    }
}
一切正常,我甚至得到日志
新数据库已复制到设备
,但是当我尝试从db读取数据时,我得到的
没有这样的表
异常


注意:我正在尝试更新我的一个旧应用程序,此代码在旧设备版本(如5.0及以下)中也适用,但当我尝试使用最新设备更新应用程序时,它不起作用。

假设您复制到资产文件夹的数据库中确实包含该表然后我认为您的问题是,您正在实例化DBHelper的一个实例,然后通过隐式或显式调用getWritableDatabase或getReadableDatabase隐式地打开数据库,然后使用onCreate方法启动复制

如果是这样,则get???ableDatabase将创建一个空数据库,副本将覆盖此内容,但在更高版本的Android 9+、以及打开数据库时,-shm和-wal文件将保持原样,然后,由于-shm和-wal文件与原始空数据库不匹配,检测到损坏,因此创建了一个新的空数据库,因为SDK代码试图提供可用的数据库

  • 默认情况下使用Android 9+,这就是创建和使用-shm和-wal文件的原因
有3个修复

  • 通过重写SQLiteOpenHelper类的onConfigure方法来使用该方法。然后使用较旧的日志模式

  • 确保未调用getWritableDatabase/getReadableDatabase。这可以通过确保在实例化DBHelper实例时完成复制来实现

  • 确保删除复制时存在的-wal和-shm文件

使用第一种模式可能只是推迟了不可避免的事情,并不是真正的建议,因为它没有利用WAL模式的好处

以下版本的DBHelper包含第二个修复程序,作为预防措施,还包含第三个修复程序:-

public class DBHelper extends SQLiteOpenHelper {

    public static final  String DB_NAME = "myDBName";
    public static String DB_PATH;

    Context context;

    public DBHelper(Context context) {
        super(context, DB_NAME, null, 2);
        this.context = context;
        //<<<<<<<<<< ADDED (moved from createDatabase) 1st Fix >>>>>>>>>>
        DB_PATH = context.getDatabasePath(DB_NAME).getAbsolutePath();
        if (!checkDataBase()) {
            copyDataBase();
        }
        //<<<<<<<<<< END OF ADDED CODE >>>>>>>>>>
        this.getWritableDatabase(); //<<<<<<<<<< Added to force an open after the copy - not essential
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //createDataBase(); <<<<<<<<<< relying on this was the cause of the issue >>>>>>>>>>
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    //<<<<<<<<<< NOT NEEDED AND SHOULD NOT BE CALLED >>>>>>>>>
    private void createDataBase() {
        boolean dbExist = checkDataBase();
        if (!dbExist) {
            copyDataBase();
        }
    }

    private boolean checkDataBase() {
        System.out.println("DB_PATH : " + DB_PATH);
        File dbFile = new File(DB_PATH);
        if (dbFile.exists()) return true;
        //<<<<<<<<<< ADDED to create the databases directory if it doesn't exist >>>>>>>>>>
        //it may be that getWritableDatabase was used to circumvent the issue that the copy would fail in the databases directory does not exist, hence this fix is included
        if (!new File(dbFile.getParent()).exists()) {
            new File(dbFile.getParent()).mkdirs();
        }
        return false;
    }

    private void copyDataBase() {
        Log.i("Database",
                "New database is being copied to device!");
        byte[] buffer = new byte[1024];
        //<<<<<<<<<< ADDED to delete wal and shm files if they exist (3rd fix) >>>>>>>>>>
        File dbDirectory = new File(new File(DB_PATH).getParent());
        File dbwal = new File(dbDirectory.getPath() + File.separator + DB_NAME + "-wal");
        if (dbwal.exists()) {
            dbwal.delete();
        }
        File dbshm = new File(dbDirectory.getPath() + File.separator + DB_NAME + "-shm");
        if (dbshm.exists()) {
            dbshm.delete();
        }
        //<<<<<<<<<< END OF ADDED CODE >>>>>>>>>>

        OutputStream myOutput;
        int length;
        InputStream myInput;
        try {
            myInput = context.getAssets().open(DB_NAME);
            myOutput = new FileOutputStream(DB_PATH);
            while ((length = myInput.read(buffer)) > 0) {
                myOutput.write(buffer, 0, length);
            }
            myOutput.close();
            myOutput.flush();
            myInput.close();
            Log.i("Database",
                    "New database has been copied to device!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
根据日志显示的结果:-

2019-05-07 06:20:53.148 I/System.out: DB_PATH : /data/user/0/soa.usingyourownsqlitedatabaseblog/databases/myDBName
2019-05-07 06:20:53.148 I/Database: New database is being copied to device!
2019-05-07 06:20:53.149 I/Database: New database has been copied to device!
2019-05-07 06:20:53.168 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@e3fe34f
2019-05-07 06:20:53.169 I/System.out: 0 {
2019-05-07 06:20:53.169 I/System.out:    type=table
2019-05-07 06:20:53.169 I/System.out:    name=Categories
2019-05-07 06:20:53.169 I/System.out:    tbl_name=Categories
2019-05-07 06:20:53.169 I/System.out:    rootpage=2
2019-05-07 06:20:53.169 I/System.out:    sql=CREATE TABLE "Categories" (
2019-05-07 06:20:53.169 I/System.out:   "not_id" integer NOT NULL,
2019-05-07 06:20:53.169 I/System.out:   "CategoryLabel" TEXT,
2019-05-07 06:20:53.169 I/System.out:   "Colour" integer,
2019-05-07 06:20:53.169 I/System.out:   PRIMARY KEY ("not_id")
2019-05-07 06:20:53.169 I/System.out: )
2019-05-07 06:20:53.170 I/System.out: }
2019-05-07 06:20:53.170 I/System.out: 1 {
2019-05-07 06:20:53.170 I/System.out:    type=table
2019-05-07 06:20:53.170 I/System.out:    name=Content
2019-05-07 06:20:53.170 I/System.out:    tbl_name=Content
2019-05-07 06:20:53.170 I/System.out:    rootpage=3
2019-05-07 06:20:53.170 I/System.out:    sql=CREATE TABLE "Content" (
2019-05-07 06:20:53.170 I/System.out:   "again_not_id" INTEGER NOT NULL,
2019-05-07 06:20:53.170 I/System.out:   "Text" TEXT,
2019-05-07 06:20:53.170 I/System.out:   "Source" VARCHAR,
2019-05-07 06:20:53.170 I/System.out:   "Category" integer,
2019-05-07 06:20:53.170 I/System.out:   "VerseOrder" integer,
2019-05-07 06:20:53.170 I/System.out:   PRIMARY KEY ("again_not_id")
2019-05-07 06:20:53.170 I/System.out: )
2019-05-07 06:20:53.170 I/System.out: }
2019-05-07 06:20:53.171 I/System.out: 2 {
2019-05-07 06:20:53.171 I/System.out:    type=table
2019-05-07 06:20:53.171 I/System.out:    name=android_metadata
2019-05-07 06:20:53.171 I/System.out:    tbl_name=android_metadata
2019-05-07 06:20:53.171 I/System.out:    rootpage=4
2019-05-07 06:20:53.171 I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
2019-05-07 06:20:53.171 I/System.out: }
2019-05-07 06:20:53.171 I/System.out: <<<<<
2019-05-07 06:20:53.148 I/System.out:DB_PATH:/data/user/0/soa.usingyourownsqlitedatabaseblog/databases/myDBName
2019-05-07 06:20:53.148 I/数据库:正在将新数据库复制到设备中!
2019-05-07 06:20:53.149 I/数据库:新数据库已复制到设备!
2019-05-07 06:20:53.168 I/System.out:>>>>>>>>转储游标android.database.sqlite。SQLiteCursor@e3fe34f
2019-05-07 06:20:53.169输入/系统输出:0{
2019-05-07 06:20:53.169输入/系统输出:类型=表
2019-05-07 06:20:53.169 I/System.out:name=类别
2019-05-07 06:20:53.169 I/System.out:tbl_name=类别
2019-05-07 06:20:53.169 I/System.out:rootpage=2
2019-05-07 06:20:53.169 I/System.out:sql=创建表“类别”(
2019-05-07 06:20:53.169 I/System.out:“not_id”整数不为空,
2019-05-07 06:20:53.169 I/System.out:“类别标签”文本,
2019-05-07 06:20:53.169输入/系统输出:“颜色”整数,
2019-05-07 06:20:53.169输入/系统输出:主键(“非id”)
2019-05-07 06:20:53.169 I/System.out:)
2019-05-07 06:20:53.170 I/System.out:}
2019-05-07 06:20:53.170输入/输出系统:1{
2019-05-07 06:20:53.170输入/系统输出:类型=表
2019-05-07 06:20:53.170输入/系统输出:名称=内容
2019-05-07 06:20:53.170输入/系统输出:待定名称=内容
2019-05-07 06:20:53.170 I/System.out:rootpage=3
2019-05-07 06:20:53.170 I/System.out:sql=创建表“内容”(
2019-05-07 06:20:53.170 I/System.out:“再次\u not \u id”整数不为空,
2019-05-07 06:20:53.170输入/系统输出:“文本”文本,
2019-05-07 06:20:53.170输入/系统输出:“源”VARCHAR,
2019-05-07 06:20:53.170输入/系统输出:“类别”整数,
2019-05-07 06:20:53.170 I/System.out:“VerseOrder”整数,
2019-05-07 06:20:53.170 I/System.out:主键(“同样不是id”)
2019-05-07 06:20:53.170 I/System.out:)
2019-05-07 06:20:53.170 I/System.out:}
2019-05-07 06:20:53.171输入/系统输出:2{
2019-05-07 06:20:53.171输入/系统输出:类型=表
2019-05-07 06:20:53.171 I/System.out:name=android\u元数据
2019-05-07 06:20:53.171 I/System.out:tbl_name=android_元数据
2019-05-07 06:20:53.171 I/System.out:rootpage=4
2019-05-07 06:20:53.171 I/System.out:sql=创建表android\u元数据(区域设置文本)
2019-05-07 06:20:53.171 I/System.out:}

2019-05-07 06:20:53.171 I/System.out:答案很好。我只使用了第三种解决方案,但请注意,我必须更改代码才能正常工作。在添加-wal之前,我添加了DB名称,在-smh中添加了DB名称(以及将=smh更改为-smh
File dbwal=new File(dbDirectory.getPath()+File.separator+DB_name+“-wal”);if(dbwal.exists()){dbwal.delete();}文件dbhm=new File(dbDirectory.getPath())+File.separator+DB_NAME+“-shm”);如果(dbshm.exists()){dbshm.delete()}
@u2tall ooops,修复了代码,感谢您指出。我个人会使用选项2,因为这样会降低资源利用率,但需要注意的是,复制的文件不能是有效的数据库(我通常会检查头的前16个字节)。
2019-05-07 06:20:53.148 I/System.out: DB_PATH : /data/user/0/soa.usingyourownsqlitedatabaseblog/databases/myDBName
2019-05-07 06:20:53.148 I/Database: New database is being copied to device!
2019-05-07 06:20:53.149 I/Database: New database has been copied to device!
2019-05-07 06:20:53.168 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@e3fe34f
2019-05-07 06:20:53.169 I/System.out: 0 {
2019-05-07 06:20:53.169 I/System.out:    type=table
2019-05-07 06:20:53.169 I/System.out:    name=Categories
2019-05-07 06:20:53.169 I/System.out:    tbl_name=Categories
2019-05-07 06:20:53.169 I/System.out:    rootpage=2
2019-05-07 06:20:53.169 I/System.out:    sql=CREATE TABLE "Categories" (
2019-05-07 06:20:53.169 I/System.out:   "not_id" integer NOT NULL,
2019-05-07 06:20:53.169 I/System.out:   "CategoryLabel" TEXT,
2019-05-07 06:20:53.169 I/System.out:   "Colour" integer,
2019-05-07 06:20:53.169 I/System.out:   PRIMARY KEY ("not_id")
2019-05-07 06:20:53.169 I/System.out: )
2019-05-07 06:20:53.170 I/System.out: }
2019-05-07 06:20:53.170 I/System.out: 1 {
2019-05-07 06:20:53.170 I/System.out:    type=table
2019-05-07 06:20:53.170 I/System.out:    name=Content
2019-05-07 06:20:53.170 I/System.out:    tbl_name=Content
2019-05-07 06:20:53.170 I/System.out:    rootpage=3
2019-05-07 06:20:53.170 I/System.out:    sql=CREATE TABLE "Content" (
2019-05-07 06:20:53.170 I/System.out:   "again_not_id" INTEGER NOT NULL,
2019-05-07 06:20:53.170 I/System.out:   "Text" TEXT,
2019-05-07 06:20:53.170 I/System.out:   "Source" VARCHAR,
2019-05-07 06:20:53.170 I/System.out:   "Category" integer,
2019-05-07 06:20:53.170 I/System.out:   "VerseOrder" integer,
2019-05-07 06:20:53.170 I/System.out:   PRIMARY KEY ("again_not_id")
2019-05-07 06:20:53.170 I/System.out: )
2019-05-07 06:20:53.170 I/System.out: }
2019-05-07 06:20:53.171 I/System.out: 2 {
2019-05-07 06:20:53.171 I/System.out:    type=table
2019-05-07 06:20:53.171 I/System.out:    name=android_metadata
2019-05-07 06:20:53.171 I/System.out:    tbl_name=android_metadata
2019-05-07 06:20:53.171 I/System.out:    rootpage=4
2019-05-07 06:20:53.171 I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
2019-05-07 06:20:53.171 I/System.out: }
2019-05-07 06:20:53.171 I/System.out: <<<<<