当我打电话时会发生什么,当我打电话SQLiteOpenHelper.close()
时会发生什么SQLiteDatabase.close()
?
对于我的 android 应用程序,我总是创建Application
具有单个实例的MySQLiteOpenHelper
类的子类,该子类的子类SQLiteOpenHelper
将由所有应用程序组件(如服务、活动和广播接收器)共享。
在MySQLiteOpenHelper
中,我有单个实例SQLiteDatabase
。我在 Application.onCreate() 方法中创建实例,并且MySQLiteOpenHelper
从不调用close()
任何实例。虽然我在每个我用来插入、更新或删除数据的游标对象上显式调用 close() 。SQLiteOpenHelper
SQLiteDatabase
query()
SQLiteStatement
到目前为止,它工作正常,没有任何问题。但最近我收到了来自用户的崩溃日志。抛出的异常是SQLiteDatabaseLockedException
. 我读了文件说
如果数据库引擎无法获取完成其工作所需的数据库锁,则抛出该异常。
我不明白当我只使用一个数据库实例并且文档说所有数据库调用都由系统序列化时,他们在获取数据库锁方面怎么会出现问题。此外,我没有使用 beginTransaction() 或任何其他相关方法开始或结束任何数据库事务。
经过一番搜索,我认为我应该调用close()
我的数据库连接。
我的问题是:
我在这里使用正确的方法吗(我不需要在其他应用程序或第 3 方应用程序之间共享数据,因此不使用 ContentProviders)?
我应该什么时候关闭数据库连接?
另外,我应该打电话给 close
MySQLiteOpenHelper
还是SQLiteDatabase
?
MySQLiteOpenHelper.java 的代码:
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
public static String TAG = Common.MAIN_TAG + "MySQLiteOpenHelper";
public static int DATABASE_VERSION = 19;
private static String DB_PATH = null;
public static final String DB_NAME = "data.sqlite";
private SQLiteDatabase db;
private final Context context;
/**
* Constructor Takes and keeps a reference of the passed context in order to
* access to the application assets and resources.
*
* @param context
*/
public MySQLiteOpenHelper(Context context) {
super(context, DB_NAME, null, DATABASE_VERSION);
DB_PATH = "/data/data/" + context.getPackageName().replace("/", "")
+ "/databases/";
this.context = context;
}
/**
* Creates a empty database on the system and rewrites it with your own
* database.
* */
public void createDataBase() throws IOException {
// Log.v(TAG, "Create database checkpoint - 1");
boolean dbExist = checkDataBase();
// Log.v(TAG, "Create database checkpoint - 2");
if (dbExist) {
// Log.v(TAG,
// "Create database checkpoint - 3 - database already exists");
} else {
// Log.v(TAG,
// "Create database checkpoint - 3 - database needs to be copied");
// Log.v(TAG, "Create database checkpoint - 4");
try {
copyDataBase();
checkDataBase();
// Log.v(TAG,
// "Create database checkpoint - 5 - database cpoied");
} catch (IOException e) {
e.printStackTrace();
throw new Error("Error copying database");
}
}
}
void copyDatabaseToSdCard() throws IOException {
if (Log.isInDebugMode()) {
InputStream input = null;
FileOutputStream output = null;
int c;
byte[] tmp;
try {
File databaseFile = new File(
Environment.getExternalStorageDirectory(),
Common.MAIN_TAG + "sqlite");
if (databaseFile.exists()) {
databaseFile.delete();
}
databaseFile.createNewFile();
output = new FileOutputStream(databaseFile);
int i = 0;
input = new FileInputStream(new File(DB_PATH + DB_NAME));
tmp = new byte[1024];
while ((c = input.read(tmp)) != -1) {
i++;
output.write(tmp, 0, c);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
input.close();
}
if (output != null) {
output.close();
output.close();
}
}
}
}
/**
* Check if the database already exist to avoid re-copying the file each
* time you open the application.
*
* @return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
// Log.v(TAG, "Check database checkpoint - 1");
SQLiteDatabase checkDB = null;
try {
// checkDB = getWritableDatabase();
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READWRITE);
// Log.v(TAG,
// "Check database checkpoint - 2 - got database file on device");
checkDB.close();
getWritableDatabase().close();
// Log.v(TAG, "Check database checkpoint - 3");
} catch (Exception e) {
// Log.v(TAG,
// "Check database checkpoint - 4 - database does not exists on device");
// database does't exist yet.
if (checkDB != null)
checkDB.close();
// Log.v(TAG, "Check database checkpoint - 5");
}
return checkDB != null ? true : false;
}
/**
* Copies your database FROM your local raw-folder to the just created empty
* database in the system folder, FROM where it can be accessed and handled.
* This is done by transfering bytestream.
* */
private void copyDataBase() throws IOException {
// Log.v(TAG, "Copy database checkpoint - 1");
InputStream input = null;
FileOutputStream output = null;
SQLiteDatabase myDB = null;
myDB = context.openOrCreateDatabase(DB_NAME, 0, null);
if (myDB != null) {
myDB.close();
}
int c;
byte[] tmp;
try {
File databaseFile = new File(DB_PATH, DB_NAME);
databaseFile.mkdirs();
databaseFile.createNewFile();
output = new FileOutputStream(DB_PATH + DB_NAME);
int i = 0;
input = context.getResources().openRawResource(R.raw.hcgtabletdb);
tmp = new byte[1024];
while ((c = input.read(tmp)) != -1) {
i++;
output.write(tmp, 0, c);
}
// Log.v(TAG, "Finished copying database");
} catch (Exception e) {
e.printStackTrace();
// Log.e(TAG, "Error in copying database" + DB_NAME);
} finally {
if (input != null) {
input.close();
}
if (output != null) {
output.close();
output.close();
}
}
}
@Override
public void onCreate(SQLiteDatabase db) {
createDataBase();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public int getIdFor(String name) {
String query = "SELECT * FROM bloodpressure WHERE userid=" + userId
+ " ORDER BY createdon, timecreatedon";
Cursor cur = db.rawQuery(query, new String[] {});
int id = cur.getInt(0);
cur.close();
return cur;
}
}
MyApplication.java 的代码
public class MyApplication extends Application {
private static MyApplication singleton;
private MySQLiteOpenHelper dbHelper;
public static MyApplication getInstance() {
return singleton;
}
@Override
public void onCreate() {
super.onCreate();
singleton = this;
dbHelper = new MySQLiteOpenHelper(getApplicationContext());
// Some code
}
public MySQLiteOpenHelper getDatabaseHelper() {
return dbHelper;
}
}
在任何应用程序组件中使用代码:
int id = MyApplication.getInstance().getDatabaseHelper().getIdFor("ashish");