我已经开发了一个使用SQLite数据库的应用程序。它将在全新安装时复制到应用程序的数据文件夹中,并且每次更新应用程序时(由于数据库是只读的,因此我会覆盖最新版本)。
这是我正在使用的代码:
public class IfcDatabase extends SQLiteOpenHelper {
private static final Object lock = new Object();
private static volatile IfcDatabase mInstance;
private SQLiteDatabase db = null;
private Context ctxt;
public static final int DATABASE_VERSION = 22;
public static final String DATABASE_NAME = "mydatabase.sqlite";
public static String DB_PATH = "";
public static IfcDatabase getInstance(Context ctx) {
IfcDatabase r = mInstance;
if (r == null) {
synchronized (lock)
{ // While we were waiting for the lock, another
r = mInstance; // thread may have instantiated the object.
if (r == null)
{
DB_PATH = ctx.getDatabasePath(DATABASE_NAME).getParent()+"/";
Log.e("logs", "DB_PATH="+DB_PATH);
r = new IfcDatabase(ctx.getApplicationContext());
mInstance = r;
}
}
}
return r;
}
private IfcDatabase(Context context) {
//super(context, DATABASE_NAME, null, DATABASE_VERSION);
super(context, DB_PATH+DATABASE_NAME, null, DATABASE_VERSION);
ctxt = context;
try {
if (!existsDatabase()) {
SQLiteDatabase tempDb = getWritableDatabase();
Log.e("logs", "Just before copying database");
copyDatabase();
Log.e("logs", "Just after copying database");
}
} catch (SQLException eSQL) {
Log.e("logs", "Error: Can not open database");
} catch (IOException IOe) {
Log.e("logs", "Error: Can not copy initial database");
}
}
private boolean existsDatabase() {
File dbFile = new File(DB_PATH + DATABASE_NAME);
return dbFile.exists();
}
public void copyDatabase() throws IOException {
AssetManager _asset = ctxt.getAssets();
InputStream myInput = _asset.open(DATABASE_NAME);
String outFileName = DB_PATH + DATABASE_NAME;
Log.e("logs", "OUTFILENAME="+outFileName);
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void openDatabase() {
db = getWritableDatabase();
Log.e("logs", "Checking if table exists (checking if database has been successfully copied)");
if(!checkIfTableExists("mytable"))
Log.e("logs", "At this moment this table doesn't exist");
else
Log.e("logs", "At this moment this table exists");
Log.e("logs", "OPEN BBDD "+db);
}
private boolean checkIfTableExists(String table_name)
{
Cursor _cursor = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='"+table_name+"'", null);
int count = _cursor.getCount();
_cursor.close();
if(count > 0)
return true;
else
return false;
}
public void closeDatabase() {
if (db != null)
db.close();
}
...
}
启动应用程序以及用户登录时调用:
IfcDatabase.getInstance(this).openDatabase();
并且只有在用户注销时它才调用:
IfcDatabase.getInstance(this).closeDatabase();
在全新安装中,将调用openDatabase,将数据库从资产复制到数据文件夹,并且用户可以开始对数据库进行查询。这些是日志:
DB_PATH=/data/user/0/com.mypackage.myapp/databases/
Just before copying database
OUTFILENAME=/data/user/0/com.mypackage.myapp/databases/mydatabase.sqlite
Just after copying database
Checking if table exists (checking if database has been successfully copied)
At this moment this table exists
OPEN BBDD SQLiteDatabase: /data/user/0/com.mypackage.myapp/databases/mydatabase.sqlite
好吧,这几乎在所有情况下都发生了(这可以正常工作),但是在某些特定的Android机型(Google Pixel和某些ZTE)中却发生了。在这些情况下,似乎此代码无法正确复制数据库。在这些情况下,在全新安装中是以下日志:
DB_PATH=/data/user/0/com.mypackage.myapp/databases/
Just before copying database
OUTFILENAME=/data/user/0/com.mypackage.myapp/databases/mydatabase.sqlite
Just after copying database
Checking if table exists (checking if database has been successfully copied)
At this moment this table doesn't exist
如您所见,数据库似乎为空或不存在。当用户进行查询时,应用程序会因以下异常而崩溃:
java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/user/0/com.mypackage.myapp/databases/mydatabase.sqlite
那么,Google Pixel和ZTE是否有可能以不同的方式使用SQLite数据库,而我的代码在这种情况下不起作用?
非常感谢您!
---编辑---
我应该补充一点,我一直在考虑这是否可能是权限问题。我请求“写入外部存储”权限,如果用户拒绝它,我要求确认,并且如果用户一直拒绝它,则该用户将无法使用该应用程序。但我几乎可以确定这与我的问题无关。
---新编辑---
我发现了一个新事物:似乎这不仅是Google Pixel问题,而且是带有Android P的Google Pixel。这让我非常担心,因为如果是与Android P相关的问题,它将在所有设备中发生。未来。
目前,我没有可以安装Android P且无法阅读Android P规范的设备,我看不到任何与数据库或内部文件相关的信息或类似信息。 有谁知道Android P是否更改了与数据库,资产,数据文件夹等相关的任何内容??
答案 0 :(得分:1)
也许您可以通过将其添加到SQLiteOpenHelper
来解决它@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
db.disableWriteAheadLogging();
}