我在Android应用中遇到了SQLite数据库的问题。它似乎经常发生,我无法重现它,但这是Android Market提供的报告。
基本上我首先有一个启动画面活动,首先检查所有需要的数据是否在数据库中。如果没有,它将在异步线程中安装数据并关闭数据库连接。
然后,只有这样才能启动主要活动,这也会打开并读取/写入数据库。
此代码从启动画面活动的onCreate方法执行:
dbWord = new WordDBAdapter(this, myUI);
dbWord.open();
if (dbWord.isDataInstalled()) {
dbWord.close();
databaseInstalled = true;
clickToStartView.setText(myUI.PRESS_TO_START);
clickToStartView.startAnimation(myBlinkAnim);
} else {
// If not, try to install in asynchronous thread
progressDialog = new ProgressDialog(this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMessage(myUI.INSTALLING_DB);
progressDialog.setCancelable(false);
new InstallDBData().execute("");
}
异步线程的代码是:
private class InstallDBData extends AsyncTask<String, Integer, Integer> {
@Override
protected Integer doInBackground(String... arg0) {
progressDialog.setProgress(0);
dbWord.installData(0, getApplicationContext());
progressDialog.setProgress(20);
dbWord.installData(1, getApplicationContext());
progressDialog.setProgress(40);
dbWord.installData(2, getApplicationContext());
progressDialog.setProgress(60);
dbWord.installData(3, getApplicationContext());
progressDialog.setProgress(80);
dbWord.installData(4, getApplicationContext());
progressDialog.setProgress(100);
return 1;
}
protected void onPreExecute() {
progressDialog.show();
}
protected void onPostExecute(Integer x) {
dbWord.close();
progressDialog.hide();
databaseInstalled = true;
clickToStartView.setText(myUI.PRESS_TO_START);
clickToStartView.startAnimation(myBlinkAnim);
}
}
这些是WordDBAdapter类的重要部分,主要活动也使用它:
public class WordDBAdapter {
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
public WordDBAdapter open() throws android.database.SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
mDbHelper.close();
}
...
}
我收到以下异常,这些异常相似但有不同的消息:
第一种错误信息:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{example.flashcards.medical/com.example.flashcards.common.SplashWindow}:
android.database.sqlite.SQLiteException: database is locked: BEGIN EXCLUSIVE;
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1830)
....
Caused by: android.database.sqlite.SQLiteException: database is locked: BEGIN EXCLUSIVE;
at android.database.sqlite.SQLiteDatabase.native_execSQL(Native Method)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1870)
at android.database.sqlite.SQLiteDatabase.beginTransactionWithListener(SQLiteDatabase.java:602)
第二类错误消息:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{example.flashcards.medical/com.example.flashcards.common.SplashWindow}:
android.database.sqlite.SQLiteException: database is locked
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1768)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1784)
....
Caused by: android.database.sqlite.SQLiteException: database is locked
at android.database.sqlite.SQLiteDatabase.native_setLocale(Native Method)
at android.database.sqlite.SQLiteDatabase.setLocale(SQLiteDatabase.java:1987)
at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1855)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:820)
at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:854)
我真的不想创建一个ContentProvider,因为我相信如果有更简单的解决方案,那就太过分了。此外,只有此应用程序才能访问数据库。
有关如何解决此问题的任何建议?
答案 0 :(得分:16)
做了一些努力之后我做到了(我的应用程序正在完善直到android 2.3但是当我以前在HoneyComb平板电脑上运行它时会出现数据库锁错误。)
我确实使用了信号量(在关键部分使用锁定)。
示例1
public class DbExp extends SQLiteOpenHelper{
public static String Lock = "dblock";
private static final String DATABASE_NAME = "db.db";
private static final String TABLE_NAME = "table_name";
public void delete(Context mContext){
synchronized(Lock) {
SQLiteDatabase db = getWritableDatabase();
db.delete(TABLE_NAME, null, null);
db.close();
}
}
public void insert(){
synchronized(Lock) {
SQLiteDatabase db = getWritableDatabase();
db.insert(TABLE_NAME, ..., ...);
db.close();
}
}
}
示例2
public class DB {
public static String Lock = "dblock";
private static final String DATABASE_NAME = "db.db";
private static final String TABLE_NAME = "table_name";
public void delete(Context mContext){
synchronized(Lock) {
SQLiteDatabase db = mContext.openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null);
db.delete(TABLE_NAME, null, null);
db.close();
}
}
public void insert(Context mContext){
synchronized(Lock) {
SQLiteDatabase db = mContext.openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null);
db.insert(TABLE_NAME, ..., ...);
db.close();
}
}
}
希望这有助于将来的任何人:)
答案 1 :(得分:5)
如果您使用Fragments并且它发生了方向更改,那么因为您有两个相同Fragment的实例,并且它们都有自己的某种Db帮助程序类的实例。为了使它工作,你要么必须在方向改变时销毁你的片段并重建它,要么找到一种方法来销毁Db助手类。这仅适用于具有方向问题的片段。我不得不做很多故障排除才能搞清楚,所以希望有人发现这个有用的
答案 2 :(得分:4)
这就是我的理由:
我忘记在插入db。之后在我的函数调用中结束事务。当我试图从另一个活动插入另一个记录时,我得到了数据库锁定异常。添加以下语句解决了我的问题。
sqlDB.endTransaction();
答案 3 :(得分:1)
我建议您在主线程中关闭数据库,然后在doInBackground方法中打开并关闭它:
@Override
protected Integer doInBackground(String... arg0)
{
db.open();
try {
// your code here
} finally {
db.close()
}
return 1;
}
此外,您不应该直接从AsyncTask调用UI方法,因为UI不是线程安全的。而是从doInBackground调用方法updateProgress并从onProgressUpdate更新progressDialog,因为onProgressUpdate是从主线程调用的。
答案 4 :(得分:1)
看起来这是一个较旧的问题,但也许这会对某人有所帮助。我遇到了同样的问题,我在一个数据库中加载了大约十几个表,并且经常会崩溃,但并非总是如此,但有时会崩溃。
最后,这可能是hackey,我刚刚为每个表创建了一个单独的数据库。所以现在我有十几个数据库,每个数据库都有一个表。但是,没有例外。代码是声音,正在创建,正确打开和关闭,似乎只是在某处发生碰撞。
就像我说过你可能会认为它是hackey,但它解决了我的问题。
分贝
答案 5 :(得分:0)
可能是因为您没有正确打开或创建数据库。如果是这样的话,试一试。
mDb = mCtx.openOrCreateDatabase(DatabaseName, SQLiteDatabase.CREATE_IF_NECESSARY, null);
DatabaseHelper类中的:
public DatabaseHelper(Context aContext)
{
mDb = aContext.openOrCreateDatabase(DatabaseName, SQLiteDatabase.CREATE_IF_NECESSARY, null);
OpenHelper openHelper = new OpenHelper(aContext, mDb );
mDb = openHelper.getWritableDatabase();
}
答案 6 :(得分:0)
这些代码行解决了我(相同)的问题:
(我之前打开了我的交易......)
writableDatabase.endTransaction();
writableDatabase.close();
dbHelper.close();