我有一个外部数据库,我将其复制到内部存储中,我在设备文件资源管理器中检查是否已成功复制它,在这里找到它,我尝试更改版本并清除应用程序存储,但没有结果
这是我得到的错误:
java.lang.RuntimeException: Unable to start activity ComponentInfo{<PackageName>.MainActivity}: android.database.sqlite.SQLiteException: no such table: MSG_CAT (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM MSG_CAT
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2914)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3049)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1809)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6680)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.database.sqlite.SQLiteException: no such table: MSG_CAT (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM MSG_CAT
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:903)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:514)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1408)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1347)
at <PackageName>.database.DatabaseHelper.getListProduct(DatabaseHelper.java:60)
at <PackageName>.MainActivity.onCreate(MainActivity.java:52)
我用来从资产文件夹创建和复制数据库的类是 :
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DBNAME = "msgDb.db";
public static final String DBLOCATION = "/data/data/<PackageName>/databases/";
private Context mContext;
private SQLiteDatabase mDatabase;
public DatabaseHelper(Context context) {
super(context, DBNAME, null, 2);
this.mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(newVersion>oldVersion)
copyDatabase(mContext);
}
public void openDatabase() {
String dbPath = mContext.getDatabasePath(DBNAME).getPath();
if (mDatabase != null && mDatabase.isOpen()) {
return;
}
mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
}
public void closeDatabase() {
if (mDatabase != null) {
mDatabase.close();
}
}
private boolean copyDatabase(Context context) {
try {
InputStream inputStream = context.getAssets().open(DatabaseHelper.DBNAME);
String outFileName = DatabaseHelper.DBLOCATION + DatabaseHelper.DBNAME;
OutputStream outputStream = new FileOutputStream(outFileName);
byte[]buff = new byte[1024];
int length = 0;
while ((length = inputStream.read(buff)) > 0) {
outputStream.write(buff, 0, length);
}
outputStream.flush();
outputStream.close();
Log.d("MainActivity","DB copied");
return true;
}catch (Exception e) {
e.printStackTrace();
return false;
}
}
public List<Category> getListProduct() {
Category category = null;
List<Category> CategoryList = new ArrayList<>();
openDatabase();
Cursor cursor = mDatabase.rawQuery("SELECT * FROM MSG_CAT", null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
category = new Category(cursor.getInt(0), cursor.getString(1), cursor.getDouble(2));
CategoryList.add(category);
cursor.moveToNext();
}
cursor.close();
closeDatabase();
return CategoryList;
}
public Category getProductById(int id) {
Category product = null;
openDatabase();
Cursor cursor = mDatabase.rawQuery("SELECT * FROM MSG_CAT WHERE ID = ?", new String[]{String.valueOf(id)});
cursor.moveToFirst();
product = new Category(cursor.getInt(0), cursor.getString(1), cursor.getDouble(2));
//Only 1 resul
cursor.close();
closeDatabase();
return product;
}
表存在证明:
我尽一切努力解决了这个问题,但没有任何结果。
我发现问题仅出在运行Android P的Pixel 2XL上,我在其他手机和模拟器上测试了该应用,并且运行良好。
答案 0 :(得分:0)
在这里,onCreate回调在您的代码中为空。使用创建表的SQLite标准语法在onCreate回调中创建表:
@Override
public void onCreate(SQLiteDatabase db) {
//execute the query to create the table with columns;
db.execSQL(YOUR_QUERY);
}
然后卸载该应用程序,然后重新安装它以重新创建包含所有表的数据库。
答案 1 :(得分:0)
为方便起见,下面的 DatabseHelper 代码不包括 getListProduct
和 getProductById
方法。
我认为从日志中可以明显看出该问题。但是基本上,如果数据库不存在,并且您要在打开数据库后复制数据库(没有数据库,它将不会被打开,因此不会进行复制)。
以下内容解决了一些问题。
主要问题是检查db文件是否位于预期位置。即它不会尝试打开数据库,而是查看文件是否存在。如果没有,它将在实例化DatabaseHelper时尝试执行任何操作来打开数据库之前复制该数据库。
此外,使用mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
打开数据库将导致打开数据库,而不会运行onUpgrade方法。那是因为您不是通过SQLiteOpenHelper子类打开数据库,所以它无济于事。
也许一个问题是您有<PackageName>
。但是,对数据库路径进行硬编码可能会引起问题,因此该路径是根据Context的 getDatabasePath 方法(强烈建议仅在不将数据库放在其他位置的情况下才使用此方法)来确定
希望以下内容可以继续进行。 注意我强烈建议删除该应用程序的数据,然后再卸载该应用程序。
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DBNAME = "msgDb.db";
public static final String DBLOCATION = "/data/data/<PackageName>/databases/"; //<<<<<<<<< Shouldn't hard code path, really this package name????
private Context mContext;
private SQLiteDatabase mDatabase;
public DatabaseHelper(Context context) {
super(context, DBNAME, null, 2);
this.mContext = context;
//<<<<<<<<<< Copy database if need be
if (!ifDBExists()) {
copyDatabase(context);
}
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.d("ONCREATE","WARNING!!!! onCreate method shopuldn't be invoked"); //<<<<<<<<<< ADDED
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion)
Log.d("ONUPGRADE","Attempting to copy database"); //<<<<<<<<<< ADDED
copyDatabase(mContext);
}
public void openDatabase() {
String dbPath = mContext.getDatabasePath(DBNAME).getPath();
if (mDatabase != null && mDatabase.isOpen()) {
return;
}
mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
}
public void closeDatabase() {
if (mDatabase != null) {
mDatabase.close();
}
}
/**
* Check if the database file exists
* @return
*/
private boolean ifDBExists() {
File db = new File(mContext.getDatabasePath(DBNAME).getPath());
if (db.exists()) return true;
File dbdir = new File(db.getParent());
if (!dbdir.exists()) {
dbdir.mkdirs();
}
return false;
}
private boolean copyDatabase(Context context) {
Log.d("COPYDATABASE","Initiating copy of database");
try {
InputStream inputStream = context.getAssets().open(DatabaseHelper.DBNAME);
String outFileName = context.getDatabasePath(DBNAME).getAbsolutePath(); //<<<<<<<<<< CHANGED
//String outFileName = DatabaseHelper.DBLOCATION + DatabaseHelper.DBNAME; // relies on hard coded
int bytes_copied = 0;
OutputStream outputStream = new FileOutputStream(outFileName);
byte[] buff = new byte[1024];
int length = 0;
while ((length = inputStream.read(buff)) > 0) {
outputStream.write(buff, 0, length);
}
outputStream.flush();
outputStream.close();
Log.d("MainActivity", "DB copied");
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public void logMsgCatTable() {
openDatabase();
Cursor csr = mDatabase.query("MSG_CAT",null,null,null,null,null, null );
DatabaseUtils.dumpCursor(csr);
}
}
按照非常基本的MainActivity运行上述程序:-
public class MainActivity extends AppCompatActivity {
DatabaseHelper mDBHlpr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDBHlpr = new DatabaseHelper(this);
mDBHlpr.logMsgCatTable();
}
}
018-11-26 11:25:47.286 2597-2597/? D/COPYDATABASE: Initiating copy of database
2018-11-26 11:25:47.287 2597-2597/? D/MainActivity: DB copied
2018-11-26 11:25:47.302 2597-2597/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@9bd3b6b
2018-11-26 11:25:47.302 2597-2597/? I/System.out: 0 {
2018-11-26 11:25:47.302 2597-2597/? I/System.out: ID=1
2018-11-26 11:25:47.302 2597-2597/? I/System.out: COL1=mcat col1 001
2018-11-26 11:25:47.303 2597-2597/? I/System.out: COL2=mcat col2 001
2018-11-26 11:25:47.303 2597-2597/? I/System.out: }
2018-11-26 11:25:47.303 2597-2597/? I/System.out: <<<<<
如上所述,除了日志中的前2条消息(即,由于DBVERSION设置为2,因此未复制DB或未运行onUpgrade)。
在SQLite工具中添加了另一行,将数据库复制回了Assets文件夹,但没有更改user_version。用修改后的数据库替换原始数据库并增加DBVERSION(super(context, DBNAME, null, 3);
)之后:-
按上述方法不会复制更新的数据库,因为onUpgrade
不会在您按助手时运行。
将代码修改为:-
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DBNAME = "msgDb.db";
public static final String DBLOCATION = "/data/data/<PackageName>/databases/"; //<<<<<<<<< Shouldn't hard code path, really this package name????
public static final int DBVERSION = 3; //<<<<<<<<<< ADDED STAGE 2
private Context mContext;
private SQLiteDatabase mDatabase;
public DatabaseHelper(Context context) {
super(context, DBNAME, null, DBVERSION); //<<<<<<<<<<CHANGED STAGE2
this.mContext = context;
//<<<<<<<<<< Copy database if need be
if (!ifDBExists()) {
copyDatabase(context);
}
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.d("ONCREATE","WARNING!!!! onCreate method shopuldn't be invoked"); //<<<<<<<<<< ADDED
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion)
Log.d("ONUPGRADE","Attempting to copy database"); //<<<<<<<<<< ADDED
copyDatabase(mContext);
}
//<<<<<<<<<< CHANGED STAGE2 (checks the user_version, closes the DB does the copy, then opens the DB)
public void openDatabase() {
String dbPath = mContext.getDatabasePath(DBNAME).getPath();
if (mDatabase != null && mDatabase.isOpen()) {
return;
}
mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
if (mDatabase.getVersion() < DBVERSION) {
mDatabase.close();
copyDatabase(mContext);
mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
}
if(!mDatabase.isOpen()) {
Log.d("OPENDATABASE","For some reason the Database cannot be opened!!!!!!!!!! ");
}
}
public void closeDatabase() {
if (mDatabase != null) {
mDatabase.close();
}
}
/**
* Check if the database file exists
* @return
*/
private boolean ifDBExists() {
File db = new File(mContext.getDatabasePath(DBNAME).getPath());
if (db.exists()) return true;
File dbdir = new File(db.getParent());
if (!dbdir.exists()) {
dbdir.mkdirs();
}
return false;
}
private boolean copyDatabase(Context context) {
Log.d("COPYDATABASE","Initiating copy of database");
try {
InputStream inputStream = context.getAssets().open(DatabaseHelper.DBNAME);
String outFileName = context.getDatabasePath(DBNAME).getAbsolutePath(); //<<<<<<<<<< CHANGED
//String outFileName = DatabaseHelper.DBLOCATION + DatabaseHelper.DBNAME; // relies on hard coded
int bytes_copied = 0;
OutputStream outputStream = new FileOutputStream(outFileName);
byte[] buff = new byte[1024];
int length = 0;
while ((length = inputStream.read(buff)) > 0) {
outputStream.write(buff, 0, length);
}
outputStream.flush();
outputStream.close();
Log.d("MainActivity", "DB copied");
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public void logMsgCatTable() {
openDatabase();
Cursor csr = mDatabase.query("MSG_CAT",null,null,null,null,null, null );
DatabaseUtils.dumpCursor(csr);
}
}
2018-11-26 12:03:28.984 3188-3188/so53468569.so53468569messages D/COPYDATABASE: Initiating copy of database
2018-11-26 12:03:28.985 3188-3188/so53468569.so53468569messages D/MainActivity: DB copied
2018-11-26 12:03:28.993 3188-3188/so53468569.so53468569messages I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@7edd361
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: 0 {
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: ID=1
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: COL1=mcat col1 001
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: COL2=mcat col2 001
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: }
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: 1 {
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: ID=2
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: COL1=mcat col1 002
2018-11-26 12:03:28.994 3188-3188/so53468569.so53468569messages I/System.out: COL2=mcat col2 002
2018-11-26 12:03:28.995 3188-3188/so53468569.so53468569messages I/System.out: }
2018-11-26 12:03:28.995 3188-3188/so53468569.so53468569messages I/System.out: <<<<<