を呼び出すSQLiteOpenHelper.close()
とどうなりますか? を呼び出すとどうなりますSQLiteDatabase.close()
か?
私のAndroidアプリケーションでは、サービス、アクティビティ、BroadcastReceiversなどのすべてのアプリケーションコンポーネントによって共有されるサブクラスであるApplication
単一のインスタンスを持つクラスのサブクラスを常に作成します。MySQLiteOpenHelper
SQLiteOpenHelper
ではMySQLiteOpenHelper
、 の単一のインスタンスがありSQLiteDatabase
ます。MySQLiteOpenHelper
私は Application.onCreate() メソッドでのインスタンスを作成し、close()
またはSQLiteOpenHelper
インスタンスを呼び出すことはありませんSQLiteDatabase
。ただし、によって返されたすべてのカーソル オブジェクトと、データの挿入、更新、または削除に使用するquery()
すべてのオブジェクトに対して明示的に close() を呼び出します。SQLiteStatement
今までは問題なく動作していました。しかし、最近、ユーザーからクラッシュログを取得しています。スローされる例外はSQLiteDatabaseLockedException
. 私は言うドキュメントを読みます
データベース エンジンがジョブを実行するために必要なデータベース ロックを取得できなかった場合にスローされます。
使用しているデータベース インスタンスが 1 つしかなく、すべてのデータベース呼び出しがシステムによってシリアル化されるとドキュメントに記載されている場合、データベース ロックを取得する際にどのように問題が発生するのかわかりません。また、beginTransaction() またはその他の関連メソッドを使用して、データベース トランザクションを開始または終了していません。
いくつかの検索の後close()
、データベース接続を呼び出す必要があると思います。
私の質問は次のとおりです。
ここで正しいアプローチを使用していますか (他のアプリやサードパーティ アプリとデータを共有する必要がないため、ContentProvider を使用しません)。
データベース接続をいつ閉じる必要がありますか?
また、私はクローズを呼び出す必要があります
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");