我想覆盖我的旧应用版本随附的现有数据库,并在下一个应用更新中覆盖新填充的数据库。但是,尽管我试图在将DB_version传递给SQLiteOpenHelper类时尝试更改它,但从未调用过onUpgrade()。
public class DataBaseHelper extends SQLiteOpenHelper {
private static Context mContext;
private static String DB_PATH = "/data/data/<app Package>/databases/";;
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.
if (sInstance == null) {
sInstance = new DataBaseHelper(context.getApplicationContext());
}
return sInstance;
}
public DataBaseHelper(Context context, String s){
super(context, DBNAME, null, version);
}
private DataBaseHelper(Context context) {
super(context, DBNAME, null, version);
mContext = context;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
} else {
DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
}
new Handler().post(new Runnable() {
@Override
public void run() {
// If u want to Copy Database from Assets.
try {
CopyAndCreateDataBase();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
// If database not exists copy it from the assets
public void CopyAndCreateDataBase() throws IOException {
boolean mDataBaseExist = checkDataBase();
if (!mDataBaseExist) {
this.getReadableDatabase();
this.getWritableDatabase();
this.close();
try {
// Copy the database from assests
copyDataBase();
String mPath = DB_PATH + DBNAME;
} catch (IOException mIOException) {
throw new Error("ErrorCopyingDataBase");
}
}
//FOR DB TESTING PURPOSES
else{
Log.d("DB STATUS:", "Database Already Exists!!!!!!!!!");
}
}
// Check that the database exists here: /data/data/yourpackage/databases/DatabaseName
private boolean checkDataBase() {
File dbFile = new File(DB_PATH + DBNAME);
// Log.v("dbFile", dbFile + " "+ dbFile.exists());
return dbFile.exists();
}
// Copy the database from assets
private void copyDataBase() throws IOException {
InputStream mInput = mContext.getAssets().open(DBNAME);
String outFileName = DB_PATH + DBNAME;
OutputStream mOutput = new FileOutputStream(outFileName);
byte[] mBuffer = new byte[1024];
int mLength;
while ((mLength = mInput.read(mBuffer)) > 0) {
mOutput.write(mBuffer, 0, mLength);
}
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) {
Log.d("Database Versions:", "old:"+i+"\nnew:"+i1);
}
}
我已经尝试了多种方法来触发onUpgrade()方法,例如调用getReadableDatabase()和getWritableDatabase(),但不幸的是,它确实奏效了。我想用新发行的数据库覆盖现有的db。
答案 0 :(得分:1)
我认为您的问题( 初始问题,请阅读完整答案 )可能正在使用处理程序。当然,测试可用的代码会导致意外的结果(数据库始终被报告为已存在,因此从不复制资产中的db,如果数据库存在则永远不会调用 onUpgrade (我猜是数据库已经打开了)由于隐式打开,因此没有尝试进行打开处理)。
正在更改使用方式:-
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
该测试在一个活动中使用了以下代码:-
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);
}
}
简而言之,存在一些问题,即使您在解决上一个问题后在调用 onUpgrade 时提高版本后就可以调用 onUpgrade ,打开并复制新数据库将被有效撤消,因为旧数据库将覆盖新复制的数据库,从而使更改丢失。
相反,我建议先执行检查,复制和覆盖数据库的操作,以实例化数据库助手,例如在 getInstance 方法中。
因此,我建议使用以下数据库助手(请参阅注释以了解所做的更改):-
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");
}
}
}
}
}
以上已通过测试。该测试基于两个数据库(完全不同),在一个活动中使用以下内容:-
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);
}
}
以下是资产文件夹:-
在两种设备API 23和API 28(Oreo so Pie +和WAL)上进行了测试。
首先,该应用程序使用上述文件运行,并且版本设置为 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 {
再次运行应用程序,无更改结果(即无数据库副本):-
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
资产文件夹中的文件更改为:-
应用重新运行不更改版本:-
无副本和原始数据:-
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
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
...........
应用再次运行(即帖子复制已完成):-
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