当我致电SQLiteOpenHelper.close()
时会发生什么?当我致电SQLiteDatabase.close()
时会发生什么?
对于我的android应用程序,我总是创建Application
类的子类,它具有MySQLiteOpenHelper
的单个实例,它是SQLiteOpenHelper
的子类,将由服务,活动等所有应用程序组件共享和BroadcastReceivers。
在MySQLiteOpenHelper
中,我有SQLiteDatabase
的单个实例。我在Application.onCreate()方法中创建了MySQLiteOpenHelper
的实例,从不在close()
或SQLiteOpenHelper
个实例上调用SQLiteDatabase
。虽然我在query()
和SQLiteStatement
返回的每个游标对象上显式调用close(),但我用来插入,更新或删除数据。
直到现在,它没有任何问题,工作正常。但最近我收到用户的崩溃日志。抛出的异常是SQLiteDatabaseLockedException
。我阅读了文件
如果数据库引擎无法获取数据库锁,则需要执行其工作。
我不明白当我只使用单个数据库实例并且文档说所有数据库调用都是由系统序列化时,他们如何在获取数据库锁时遇到问题。此外,我不是使用beginTransaction()或任何其他相关方法开始或结束任何数据库事务。
经过一番搜索后,我认为我应该在数据库连接上调用close()
。
我的问题是:
我在这里使用了正确的方法(我不需要在其他应用程序或第三方应用程序之间共享数据,因此不使用ContentProviders)?
何时应关闭数据库连接?
此外,我应该致电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");
答案 0 :(得分:1)
SQLiteOpenHeloper::close()
和SQLiteDatabase::close()
之间没有区别。
SQLiteOpenHeloper::close()
只是SQLiteDatabase::close()
的包装。
但是根据经验,要么SQLiteOpenHelper
管理您的连接,要么不使用它并自行管理。
请参阅此博文。我将SQLiteOpenHelper
与我自己的预加载数据库一起使用,但与SQLiteOpenHelper
很好地配合,让它管理连接。
using a pre-loaded sqlite database with SQLiteOpenHelper
<强>更新强>
这是SQLiteOpenHelper::close()
的源代码:
/**
* Close any open database object.
*/
public synchronized void close() {
if (mIsInitializing) throw new IllegalStateException("Closed during initialization");
if (mDatabase != null && mDatabase.isOpen()) {
mDatabase.close();
mDatabase = null;
}
}