7

を呼び出すSQLiteOpenHelper.close()とどうなりますか? を呼び出すとどうなりますSQLiteDatabase.close()か?

私のAndroidアプリケーションでは、サービス、アクティビティ、BroadcastReceiversなどのすべてのアプリケーションコンポーネントによって共有されるサブクラスであるApplication単一のインスタンスを持つクラスのサブクラスを常に作成します。MySQLiteOpenHelperSQLiteOpenHelper

ではMySQLiteOpenHelper、 の単一のインスタンスがありSQLiteDatabaseます。MySQLiteOpenHelper私は Application.onCreate() メソッドでのインスタンスを作成し、close()またはSQLiteOpenHelperインスタンスを呼び出すことはありませんSQLiteDatabase。ただし、によって返されたすべてのカーソル オブジェクトと、データの挿入、更新、または削除に使用するquery()すべてのオブジェクトに対して明示的に close() を呼び出します。SQLiteStatement

今までは問題なく動作していました。しかし、最近、ユーザーからクラッシュログを取得しています。スローされる例外はSQLiteDatabaseLockedException. 私は言うドキュメントを読みます

データベース エンジンがジョブを実行するために必要なデータベース ロックを取得できなかった場合にスローされます。

使用しているデータベース インスタンスが 1 つしかなく、すべてのデータベース呼び出しがシステムによってシリアル化されるとドキュメントに記載されている場合、データベース ロックを取得する際にどのように問題が発生するのかわかりません。また、beginTransaction() またはその他の関連メソッドを使用して、データベース トランザクションを開始または終了していません。

いくつかの検索の後close()、データベース接続を呼び出す必要があると思います。

私の質問は次のとおりです。

  1. ここで正しいアプローチを使用していますか (他のアプリやサードパーティ アプリとデータを共有する必要がないため、ContentProvider を使用しません)。

  2. データベース接続をいつ閉じる必要がありますか?

  3. また、私はクローズを呼び出す必要がありますMySQLiteOpenHelperSQLiteDatabase

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");
4

1 に答える 1

2

SQLiteOpenHeloper::close()と の間に違いはありませんSQLiteDatabase::close()

SQLiteOpenHeloper::close()は単なるラッパーSQLiteDatabase::close()です。

ただし、経験則として、let でSQLiteOpenHelper接続を管理するか、使用せずに自分で管理します。

このブログ投稿を参照してください。私は自分の事前にロードされたデータベースを使用していますが、接続を管理できるように でSQLiteOpenHelperうまく遊んでいます。SQLiteOpenHelper

SQLiteOpenHelper でプリロードされた sqlite データベースを使用する

更新 これはのソースコードです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;
    }
}
于 2012-09-25T09:18:08.667 に答える