我相信你的问题(第一期,请阅读完整答案)可能正在使用处理程序。当然,测试可用代码会导致意外结果(数据库始终报告为存在,因此永远不会从资产中复制数据库,如果数据库存在,则永远不会调用升级时(我的猜测是,由于隐式打开,数据库已经打开,因此没有尝试进行打开处理))。
更改为使用:-
try {
CopyAndCreateDataBase();
} catch (IOException e) {
e.printStackTrace();
}
/*
new Handler().post(new Runnable() {
@Override
public void run() {
// If u want to Copy Database from Assets.
try {
CopyAndCreateDataBase();
} catch (IOException e) {
e.printStackTrace();
}
}
});
*/
产生预期的结果,例如:-
07-04 06:55:38.836 4365-4365/aso.so56873021recopydb D/DBEXISTS: The database /data/user/0/aso.so56873021recopydb/databases/DB.db was found.
07-04 06:55:38.836 4365-4365/aso.so56873021recopydb D/DB STATUS:: Database Already Exists!!!!!!!!!
07-04 06:55:38.838 4365-4365/aso.so56873021recopydb D/Database Versions:: old:1
new:2
- 请注意,在测试代码以确定问题时添加了 DBEXISTS 消息。
测试在活动中使用了以下代码:-
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DataBaseHelper mDBHlpr = DataBaseHelper.getInstance(this);
Cursor csr = mDBHlpr.getWritableDatabase().query("sqlite_master",null,null,null,null,null,null);
DatabaseUtils.dumpCursor(csr);
}
}
第 2 部分 - 升级
简而言之,即使您可以致电,也存在问题升级时当修复上一个问题后版本增加时升级时被调用时,数据库已经打开,复制新数据库将被有效地撤消,因为旧数据库将覆盖新复制的数据库,从而导致更改丢失。
相反,我建议检查、复制和覆盖数据库prior实例化数据库助手,例如在里面获取实例 method.
因此,我建议使用以下数据库助手(请参阅所做更改的评论):-
public class DataBaseHelper extends SQLiteOpenHelper {
private static Context mContext;
//private static String DB_PATH = "/data/data/<app Package>/databases/"; //NOT NEEDED Contexts getDatabasePath used instead
private static final String DBNAME = "DB.db";
private static DataBaseHelper sInstance;
private static final int version = 2;
public static synchronized DataBaseHelper getInstance(Context context) {
// Use the application context, which will ensure that you
// don't accidentally leak an Activity's context.
checkDB(context.getApplicationContext(),DBNAME,version); //<<<<<<<<<< do the stuff before DatabaseHelper instantiation
if (sInstance == null) {
sInstance = new DataBaseHelper(context.getApplicationContext());
}
return sInstance;
}
private DataBaseHelper(Context context) {
super(context, DBNAME, null, version);
mContext = context;
}
// Copy the database from assets
//<<<<<<<<<< CHANGED TO USE getDatabasepath requiring Context to be passed
private static void copyDataBase(Context context) throws IOException {
InputStream mInput = context.getAssets().open(DBNAME);
String outFileName = context.getDatabasePath(DBNAME).toString();
OutputStream mOutput = new FileOutputStream(outFileName);
Log.d("DBCOPY","DB Copy inititaed"); //<<<<<<<<<< ADDED FOR TESTING
byte[] mBuffer = new byte[1024];
int mLength;
int bytescopied = 0;
while ((mLength = mInput.read(mBuffer)) > 0) {
mOutput.write(mBuffer, 0, mLength);
bytescopied = bytescopied + mLength;
}
Log.d("DBCOPY", "Database copied. " + String.valueOf(bytescopied) + " bytes copied." ); //<<<<<<<<<< ADDED FOR TESTING
Log.d("DB STATUS:", "Daatabase Created ----------------"); //FOR DB TESTING PURPOSES
mOutput.flush();
mOutput.close();
mInput.close();
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//<<<<<<<<<< ONLY USE ME FOR SCHEMA CHANGES !!!!NOT!!!! new DB copy
Log.d("Database Versions:", "old:"+i+"\nnew:"+i1);
}
//<<<<<<<<<< NEW
private static void checkDB(Context context, String dbname, int version) {
int dbversion;
// Note uses the Contexts getDatabasePath
File dbfile = new File(context.getDatabasePath(dbname).toString());
if (!dbfile.exists()) {
//<<<<<<<<<< create the databases directory (or whatever it is the future)
if (!dbfile.getParentFile().exists()) {
dbfile.getParentFile().mkdirs();
}
//<<<<<<<<<< Now do the copy of the initial DB
//<<<<<<<<<< Note new install will copy the latest DB
try {
copyDataBase(context);
} catch (IOException e) {
e.printStackTrace();
throw new Error("Error copying initial Database.");
}
}
// If the database file does exist then retrieve the version
else {
SQLiteDatabase db = SQLiteDatabase.openDatabase(context.getDatabasePath(dbname).toString(),null,SQLiteDatabase.OPEN_READWRITE);
dbversion = db.getVersion();
Log.d("DBVERSION","The stored database version is " + String.valueOf(dbversion));
db.close();
//<<<<<<<<<< if the database's version is less than the coded version then copy the DB
//<<<<<<<<<< NOTE!!!! always assumes new version = new copy
//<<<<<<<<<< IF NOt WANTED THEN DO SPECIFIC VERSION CHECKING
if (dbversion < version) {
//<<<<<<<<<<<< EXAMPLE skip copy on version 10 >>>>>>>>>>
//<TODO> Remove example check if not needed
if (dbversion < version && version == 10) {
return;
}
//<<<<<<<<<< For Android 9+ delete the -wal and -shm files if copying database
if (new File(context.getDatabasePath(dbname).toString() + "-wal").exists()) {
new File(context.getDatabasePath(dbname).toString() + "-wal").delete();
}
if (new File(context.getDatabasePath(dbname).toString() + "-shm").exists()) {
new File(context.getDatabasePath(dbname).toString() + "-shm").delete();
}
try {
copyDataBase(context);
} catch (IOException e) {
e.printStackTrace();
throw new Error("Error copying upgraded database");
}
}
}
}
}
Testing
以上已经测试过。测试基于两个数据库(完全不同),在活动中使用以下内容:-
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DataBaseHelper mDBHlpr = DataBaseHelper.getInstance(this);
Cursor csr = mDBHlpr.getWritableDatabase().query("sqlite_master",null,null,null,null,null,null);
DatabaseUtils.dumpCursor(csr);
}
}
以下是资产文件夹:-
- 原始数据库被OLDDB.db复制到DB.db。 NEWDB.db 将是后续的新数据库。
测试在 API 23 和 API 28(Oreo so Pie+ 和 WAL)两种设备上进行。
Stage 1
首先,应用程序使用上述文件运行,版本设置为1。导致日志包含:-
07-04 10:20:32.120 8154-8154/aso.so56873021recopydb D/DBCOPY: DB Copy inititaed
07-04 10:20:32.120 8154-8154/aso.so56873021recopydb D/DBCOPY: Database copied. 36864 bytes copied.
07-04 10:20:32.120 8154-8154/aso.so56873021recopydb D/DB STATUS:: Daatabase Created ----------------
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@6e2c433
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: 0 {
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: type=table
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: name=android_metadata
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: tbl_name=android_metadata
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: rootpage=3
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: }
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: 1 {
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: type=table
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: name=room_master_table
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: tbl_name=room_master_table
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: rootpage=4
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: sql=CREATE TABLE room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)
07-04 10:20:32.140 8154-8154/aso.so56873021recopydb I/System.out: }
..........
API 28 设备上的类似结果:-
2019-07-04 10:22:33.082 4532-4532/aso.so56873021recopydb D/DBCOPY: DB Copy inititaed
2019-07-04 10:22:33.083 4532-4532/aso.so56873021recopydb D/DBCOPY: Database copied. 36864 bytes copied.
2019-07-04 10:22:33.083 4532-4532/aso.so56873021recopydb D/DB STATUS:: Daatabase Created ----------------
2019-07-04 10:22:33.088 4532-4532/aso.so56873021recopydb I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@2f7f7bc
2019-07-04 10:22:33.089 4532-4532/aso.so56873021recopydb I/System.out: 0 {
Stage 2
应用程序再次运行,结果没有变化(即没有数据库副本):-
07-04 10:24:13.642 8244-8244/? D/DBVERSION: The stored database version is 1
07-04 10:24:13.644 8244-8244/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@8c743f0
在 API 28 设备上:-
2019-07-04 10:26:24.531 4620-4620/? D/DBVERSION: The stored database version is 1
2019-07-04 10:26:24.536 4620-4620/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@877f345
Stage 3
资产文件夹中的文件更改为:-
应用程序重新运行无需更改版本 :-
无副本和原始数据:-
07-04 10:30:01.838 8369-8369/? D/DBVERSION: The stored database version is 1
07-04 10:30:01.840 8369-8369/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@8c743f0
07-04 10:30:01.840 8369-8369/? I/System.out: 0 {
07-04 10:30:01.840 8369-8369/? I/System.out: type=table
07-04 10:30:01.840 8369-8369/? I/System.out: name=android_metadata
07-04 10:30:01.840 8369-8369/? I/System.out: tbl_name=android_metadata
07-04 10:30:01.840 8369-8369/? I/System.out: rootpage=3
07-04 10:30:01.840 8369-8369/? I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
07-04 10:30:01.840 8369-8369/? I/System.out: }
07-04 10:30:01.840 8369-8369/? I/System.out: 1 {
07-04 10:30:01.840 8369-8369/? I/System.out: type=table
07-04 10:30:01.840 8369-8369/? I/System.out: name=room_master_table
在 API 28 上:-
2019-07-04 10:31:11.591 4757-4757/aso.so56873021recopydb D/DBVERSION: The stored database version is 1
2019-07-04 10:31:11.596 4757-4757/aso.so56873021recopydb I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@877f345
2019-07-04 10:31:11.596 4757-4757/aso.so56873021recopydb I/System.out: 0 {
2019-07-04 10:31:11.596 4757-4757/aso.so56873021recopydb I/System.out: type=table
2019-07-04 10:31:11.596 4757-4757/aso.so56873021recopydb I/System.out: name=android_metadata
2019-07-04 10:31:11.596 4757-4757/aso.so56873021recopydb I/System.out: tbl_name=android_metadata
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out: rootpage=3
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out: }
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out: 1 {
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out: type=table
2019-07-04 10:31:11.597 4757-4757/aso.so56873021recopydb I/System.out: name=room_master_table
Stage 4
version increased from 1 to 2 :-
07-04 10:38:42.679 8857-8857/? D/DBVERSION: The stored database version is 1
07-04 10:38:42.679 8857-8857/? D/DBCOPY: DB Copy inititaed
07-04 10:38:42.680 8857-8857/? D/DBCOPY: Database copied. 77824 bytes copied.
07-04 10:38:42.680 8857-8857/? D/DB STATUS:: Daatabase Created ----------------
07-04 10:38:42.683 8857-8857/? D/Database Versions:: old:1
new:2
07-04 10:38:42.688 8857-8857/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@f2b3d69
07-04 10:38:42.688 8857-8857/? I/System.out: 0 {
07-04 10:38:42.688 8857-8857/? I/System.out: type=table
07-04 10:38:42.688 8857-8857/? I/System.out: name=android_metadata
07-04 10:38:42.688 8857-8857/? I/System.out: tbl_name=android_metadata
07-04 10:38:42.688 8857-8857/? I/System.out: rootpage=3
07-04 10:38:42.689 8857-8857/? I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
07-04 10:38:42.689 8857-8857/? I/System.out: }
07-04 10:38:42.689 8857-8857/? I/System.out: 1 {
07-04 10:38:42.689 8857-8857/? I/System.out: type=table
07-04 10:38:42.689 8857-8857/? I/System.out: name=shops
07-04 10:38:42.689 8857-8857/? I/System.out: tbl_name=shops
07-04 10:38:42.689 8857-8857/? I/System.out: rootpage=4
07-04 10:38:42.689 8857-8857/? I/System.out: sql=CREATE TABLE shops (_id INTEGER PRIMARY KEY , shoporder INTEGER DEFAULT 1000 , shopname TEXT , shopstreet TEXT , shopcity TEXT , shopstate TEXT , shopnotes TEXT )
07-04 10:38:42.689 8857-8857/? I/System.out: }
........
在 API 28 上:-
2019-07-04 10:40:31.799 5010-5010/aso.so56873021recopydb D/DBVERSION: The stored database version is 1
2019-07-04 10:40:31.800 5010-5010/aso.so56873021recopydb D/DBCOPY: DB Copy inititaed
2019-07-04 10:40:31.802 5010-5010/aso.so56873021recopydb D/DBCOPY: Database copied. 77824 bytes copied.
2019-07-04 10:40:31.802 5010-5010/aso.so56873021recopydb D/DB STATUS:: Daatabase Created ----------------
2019-07-04 10:40:31.826 5010-5010/aso.so56873021recopydb D/Database Versions:: old:1
new:2
...........
Stage 5
应用程序再次运行(即发布复制已完成):-
07-04 10:41:53.653 8947-8947/? D/DBVERSION: The stored database version is 2
07-04 10:41:53.655 8947-8947/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@8c743f0
07-04 10:41:53.655 8947-8947/? I/System.out: 0 {
07-04 10:41:53.655 8947-8947/? I/System.out: type=table
07-04 10:41:53.655 8947-8947/? I/System.out: name=android_metadata
07-04 10:41:53.655 8947-8947/? I/System.out: tbl_name=android_metadata
07-04 10:41:53.655 8947-8947/? I/System.out: rootpage=3
07-04 10:41:53.655 8947-8947/? I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
07-04 10:41:53.655 8947-8947/? I/System.out: }
07-04 10:41:53.655 8947-8947/? I/System.out: 1 {
07-04 10:41:53.655 8947-8947/? I/System.out: type=table
07-04 10:41:53.655 8947-8947/? I/System.out: name=shops
07-04 10:41:53.655 8947-8947/? I/System.out: tbl_name=shops
在 API 28 上:-
2019-07-04 10:42:41.296 5098-5098/aso.so56873021recopydb D/DBVERSION: The stored database version is 2
2019-07-04 10:42:41.306 5098-5098/aso.so56873021recopydb I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@877f345
2019-07-04 10:42:41.307 5098-5098/aso.so56873021recopydb I/System.out: 0 {
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: type=table
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: name=android_metadata
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: tbl_name=android_metadata
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: rootpage=3
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: }
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: 1 {
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: type=table
2019-07-04 10:42:41.308 5098-5098/aso.so56873021recopydb I/System.out: name=shops
2019-07-04 10:42:41.309 5098-5098/aso.so56873021recopydb I/System.out: tbl_name=shops