7

当我打电话时会发生什么,当我打电话SQLiteOpenHelper.close()时会发生什么SQLiteDatabase.close()

对于我的 android 应用程序,我总是创建Application具有单个实例的MySQLiteOpenHelper类的子类,该子类的子类SQLiteOpenHelper将由所有应用程序组件(如服务、活动和广播接收器)共享。

MySQLiteOpenHelper中,我有单个实例SQLiteDatabase。我在 Application.onCreate() 方法中创建实例,并且MySQLiteOpenHelper从不调用close()任何实例。虽然我在每个我用来插入、更新或删除数据的游标对象上显式调用 close() 。SQLiteOpenHelperSQLiteDatabasequery()SQLiteStatement

到目前为止,它工作正常,没有任何问题。但最近我收到了来自用户的崩溃日志。抛出的异常是SQLiteDatabaseLockedException. 我读了文件说

如果数据库引擎无法获取完成其工作所需的数据库锁,则抛出该异常。

我不明白当我只使用一个数据库实例并且文档说所有数据库调用都由系统序列化时,他们在获取数据库锁方面怎么会出现问题。此外,我没有使用 beginTransaction() 或任何其他相关方法开始或结束任何数据库事务。

经过一番搜索,我认为我应该调用close()我的数据库连接。

我的问题是:

  1. 我在这里使用正确的方法吗(我不需要在其他应用程序或第 3 方应用程序之间共享数据,因此不使用 ContentProviders)?

  2. 我应该什么时候关闭数据库连接?

  3. 另外,我应该打电话给 closeMySQLiteOpenHelper还是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");
4

1 回答 1

2

SQLiteOpenHeloper::close()和之间没有区别SQLiteDatabase::close()

SQLiteOpenHeloper::close()只是一个包装SQLiteDatabase::close()

但根据经验,要么让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 回答