Я изменил свой класс DatabaseHelper, чтобы использовать библиотеку SQLCipher.
Для этого я:
Скопировал активы в папку с моими активами и библиотеки (armeabi, x86, commons-codec, guava-r09, sqlcipher) в папку с моими библиотеками.
Изменил импорт в моем классе
DatabaseHelper
, чтобы вместо этого они указывали наimport net.sqlcipher.database.*
.Позвоните
SQLiteDatabase.loadLibs(getApplicationContext());
, когда приложение запустится.Изменил строки, где я вызываю
getReadableDatabase()
иgetWriteableDatabase()
, чтобы они включали парольную фразу в качестве параметра;
Кажется, все работает нормально, данные читаются/записываются правильно. Моя проблема связана с производительностью, так как мое приложение может выполнять операции с БД с некоторой частотой, что приводит к его замедлению (после перехода на SQLCipher).
Для моих методов DatabaseHelper я придерживаюсь стандартного подхода, например:
/*
* Getting all MyObjects
*/
public List<MyObject> getMyObjects() {
List<MyObject> objects = new ArrayList<MyObject>();
String selectQuery = "SELECT * FROM " + TABLE_NAME;
Log.v(LOG, selectQuery);
// Open
SQLiteDatabase db = this.getReadableDatabase("...the password...");
// I know this passphrase can be figured out by decompiling.
// Cursor with query
Cursor c = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (c.moveToFirst()) {
do {
MyObject object = createMyObjectFromCursor(c); // Method that builds MyObject from Cursor data
// adding to list
objects.add(object);
} while (c.moveToNext());
}
c.close();
db.close();
return objects;
}
Я не совсем знаком с внутренней механикой SQLCipher (например, расшифровывает ли он весь файл БД, когда я вызываю getReadableDatabase()
?), но во время отладки кажется, что накладные расходы находятся в getReadableDatabase(password)
и getWritableDatabase(password)
, что имеет смысл, если мое предположение выше правда.
Будет ли плохой практикой перемещение этих вызовов в методы DatabaseHelper.open() и DatabaseHelper.close(), которые будут вызываться Activity всякий раз, когда они создают экземпляр DatabaseHelper, вместо того, чтобы вызывать их для каждого отдельного метода? Поделитесь, пожалуйста, своими знаниями о том, как решить эту проблему.
ИЗМЕНИТЬ:
Я использовал DDMS для отслеживания одного из методов и вижу, что накладные расходы действительно составляют SQLiteOpenHelper.getReadableDatabase()
(каждый раз это занимает ~4 секунды). Запросы, кажется, работают быстро, и я не думаю, что мне нужно беспокоиться о них.
Если я разверну вызовы, каждый раз следуя за вызовом с наибольшей продолжительностью, я получаю:
SQLiteDatabase.OpenOrCreateDatabase
--> SqLiteDatabase.openDatabase
--> SQLiteDatabase.openDatabase
--> SQLiteDatabase.setLocale
Таким образом, SQLiteDatabase.setLocale(java.util.Locale)
кажется виновником, поскольку каждый раз, когда вызывается getReadableDatabase(), требуется ~ 4 секунды. Я просмотрел источник для SQLiteDatabase, и он просто блокирует БД, вызывает native_setLocale(locale.toString(), mFlags)
(здесь имеют место 4-секундные накладные расходы) и разблокирует БД.
Любая идея о том, почему это происходит?