Управление базой данных в Android (часть 2)

В процессе работы с sqlite базой выяснилось, что не всё так просто, как казалось в [[http://blog.arkoniak.com/?p=181|Управление базой данных]]. Выяснилось несколько особенностей реализации sqlite под андроидом.

# Начиная с какой-то (видимо довольно древней) версии android, все sql запросы по умолчанию оборачиваются в транзакцию. Поэтому нельзя ставить “BEGIN TRANSACTION”, “COMMIT”, вместо этого надо использовать beginTransaction(), setTransactionSuccessful() и endTransaction(). В этом случае компилятор самостоятельно правильным образом расставит точки сохранения и откатов.
# Драйвер sqlite, как выяснилось не поддерживает множественные запросы в одной команде, то есть если будет передана последовательность команд разделённых точкой с запятой, то выполнится только самая первая. Это решать можно многими разными способами, я сделал максимально примитивно и группирую запросы в массив, по которому затем последовательно пробегаю в цикле. Возможно имеет смысл сделать какую-то более изящную конструкцию, но в принципе работает и так.

{{{lang=java
String sql_query_1 = “SOME QUERY;”;
String sql_query_2 = “SOME OTHER QUERY;”;
String[] queries = new String[]{sql_query_1, sql_query_2};

….
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch(oldVersion) {
case 1:
db.beginTransaction();
try{
for (String str : queries){
db.execSQL(str);
}
db.setTransactionSuccessful();
}
catch (Exception e){
// Exception processing
}
finally{
db.endTransaction();
}
}
}
}}}

Топ 10 горячих клавиш Eclipse

Следующий текст – это перевод статьи [[http://sureshkrishna.wordpress.com/2007/09/15/top-10-eclipse-shotcuts/|Top 10 eclipse hotkeys]].

Многие из тех, кто использует eclipse больше чем год привыкли к использованию горячих клавиш. Процесс запоминания всевозможных комбинаций довольно трудоёмок и конечно же нет никакой необходимости помнить их все. Ниже приведены наиболее часто используемые комбинации, которые собраны на основе достаточно длительного опыта использования в процессе разработки.

* Ctrl + Shift + O : Organize imports
* Ctrl + Shift + T : Open Type
* Ctrl + Shift + F4 : Close all Opened Editors
* Ctrl + O : Open declarations
* Ctrl + E : Open Editor
* Ctrl + / : Line Comment
* Alt + Shift + R : Rename
* Alt + Shift + L : extract to Local Variable
* Alt + Shift + M : extract to Method
* F3 : Open Declaration

Позвольте объяснить, в каких ситуациях используются эти горячие клавиши.

* Я начал разрабатывать плагин. По мере процесса разработки постоянно возникает потребность в рефакторинге кода при помощи комбинации клавиш “Alt + Shift + L” или “Alt + Shift + L” и “Alt + Shift + M“.
* В результате у меня множество методов и вероятно более 500 строчек кода в каждом. Типичный процесс разработки включает в себя комментирование и раскомментирование при помощи “Ctrl + /” (хотя существует возможность блочного комментирования по ряду причин многие разработчики предпочитают использовать “Ctrl + /”).
* По мере комментирования и раскомментирования кода, необходимо регулярно чистить import. Например классы часто копируется из одного файла в другой и поэтому удобно организовывать imports при помощи “Ctrl + Shift + O“
* Когда возникает потребность в том, чтобы найти определение переменной или метода, удобно использовать “Ctrl + O“.
* В процессе разработки, желательно видеть/проанализировать описание метода или класса, и для этого удобно нажимать “F3″.
* Пока что всё идёт хорошо и я хочу использовать интерфейс/класс и для этого ищу его через “Ctrl + Shift + T“.
* К этому моменту у нас накопилось слишком большое количество открытых редакторов и по ним удобно осуществлять навигацию при помощи “Ctrl + E“.
* И наконец, вы не выдерживаете и закрываете все окна при помощи “Ctrl + Shift + F4“.

Управление базой данных в Android

В процессе разработки с androidом и, соответственно, разработки под sqlite базу данных, возникает ряд задач. Ниже описаны сами задачи и их решения.

1. **Извлечение базы данных из устройства**
Конечно, программно управлять базой хорошо, но иногда возникает желание посмотреть как физически выглядит полученный результат. Особенно ярко это желание возникает, когда происходит апгрейд базы и соответственно требуется оценить, правильно ли он произошёл или разработчик что-нибудь забыл сделать в процессе.

Решается это с помощью утилиты adb, которая идёт в комплекте с android sdk. Находится она в директории platform-tools.
{{{lang=bash
> cd /platofrm-tools
> ./adb shell ‘cp /data/data/<название приложения, допустим com.my.app>
/databases/.db /sdcard/.db’
> ./adb pull /sdcard/.db
}}}

Тут есть несколько моментов, на которые стоит обратить внимание. Во-первых, утилита adb в принципе очень полезная, и команда adb shell запускает команду на устройстве, и в неё можно передавать обычные юниксовые команды. Например, если вы не очень понимаете, какова структура папок конкретно у вас на устройстве, то можно сделать
{{{ lang=bash
> ./adb shell ‘ls -al /data’
}}}
и дальше обычным образом просмотреть всю файловую структуру устройства, что обычно очень удобно для понимания происходящего.

Во-вторых, у меня телефон рутованый, поэтому возможно что указанная команда не будет выполнена. На форумах и stackoverflow советуют в этом случае исполнить
{{{lang=bash
> ./adb shell ‘run-as <название приложения, допустим com.my.app> cat
/data/data/<название приложения, допустим com.my.app>/databases/
.db > /sdcard/.db’
}}}

2. **Миграция баз данных**
При миграции базы возникает проблема корректного обновления старой версии базы до новой. Естественно, что если у вас база переходит с версии 1 на версию 2, то написать миграционный скрипт не сложно. Но если миграций штук десять и пользователь может перейти с любой версии на любую, то хотелось бы иметь хорошо управляемую систему, которая бы автоматически отслеживала любые возможные ситуации и применяла корректную последовательность миграций. На stackoverflow нашлось отличное решение этой проблемы. Как известно, миграция происходит при вызове метода onUpgrade, который принимает в себя номер старой и новой версии. Так вот, проблему корректных миграций решает следующая структура
{{{lang=java
onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch(oldVersion) {
case 1:
db.execSQL(DATABASE_CREATE_SOMETHING);
// we want both updates, so no break statement here…
case 2:
db.execSQL(DATABASE_CREATE_SOMETHINGELSE);
}
}
}}}
Ключевым моментом является идея о том, что между разными case не надо ставить break! В этом случае изменения начнут применяться с правильной версии и будут накатываться до самого конца.

3. **Изменение существующих таблиц**
Помимо проблемы корректной миграции есть ещё задача правильного изменения уже существующих таблиц. В большинстве больших баз данных (типа postgre) есть масса команд вроде ALTER TABLE ALTER COLUMN, которые позволяют поменять тип колонки, добавить/удалить constraints, удалять колонки и сделать много много чего ещё. К сожалению, sqlite намного более ограничен в этом вопросе, и хотя у него есть частично подобный функционал, но он мягко говоря неудобен. Но решение существует, и общая идея состоит в том, что создаётся временная таблица, в которую копируется существующая, после чего существующая удаляется и на её месте создаётся новая с новыми правилами. В эту новую таблицу вставляются данные из бэкапа, который затем удаляется. Минус в том, что создаются промежуточные таблицы, и операции вставки занимают довольно много времени и процессорных ресурсов. С другой стороны, sqlite базы редко бывают большими, особенно на android, так что вряд ли это такая уж серьёзная проблема.
{{{lang=sql
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t1_backup(a,b);
INSERT INTO t1_backup SELECT a,b FROM t1;
DROP TABLE t1;
CREATE TABLE t1(a,b);
INSERT INTO t1 SELECT a,b FROM t1_backup;
DROP TABLE t1_backup;
COMMIT
}}}

Размещения андроид приложения

Мои первые впечатления от попыток размещения андроид приложения на профильных сайтах следующие:
# отечественные сайты отвечают по большей части достаточно не быстро (может им это просто не очень интересно или влияет то, что праздники ещё не закончились…);
# некоторые из сайтов делают очень на мой взгляд странную ошибку – не оставляют контактов для связи с собой. Наверное боятся, что за ними будут гоняться правообладатели и поэтому шифруются 🙂 Но для таких людей как я, увы, подобные сайты становятся совсем бесполезными;
# часть сайтов согласна размещать бесплатные приложения бесплатно, однако, есть сайты, которые даже бесплатные программы хотят размещать только за деньги. Впрочем, деньги просят не очень большие. Но для меня даже это оверкилл, так как пишу по большей части для собственного удовольствия, чем для заработка.

Среди всех тех, с кем я связался, больше всех благодарен сайту [[http://www.ppccabfiles.ru|PPCCABFILES.ru]]

Помимо того, что они написали отличный промо обзор, так к тому же сделали видео [[http://www.youtube.com/watch?v=BMTvcx0N4oE|http://www.youtube.com/watch?v=BMTvcx0N4oE]]! У меня до этого руки увы не дошли, поэтому я им чрезвычайно благодарен!

Запуск Piggy Bank

Download Piggy Bank / Android

С гордостью объявляю, что я выпустил в свет моё первое (но надеюсь не последнее) андроид приложение, называющееся Piggy Bank (или Свинья-Копилка по русски).

|[[image:sc1_tb.png|100px|link=source]]|[[image:sc2_tb.png|100px|link=source|right]]|[[image:sc3_tb.png|100px|link=source]]|[[image:sc4_tb.png|100px|link=source|right]]|

Скачать его можно по этой ссылке
[[https://play.google.com/store/apps/details?id=com.arkoniak.piggybank|https://play.google.com/store/apps/details?id=com.arkoniak.piggybank]]

С помощью этого приложения можно решать очень простую задачу: если вы хотите накопить какую-то сумму в течение некоторого времени, то с помощью Свиньи-Копилки вы будете знать сколько времени уже прошло, сколько времени осталось и успеваете ли вы накопить деньги в срок.

Дополнительно, в программе хранится информация о всех предыдущих попытках накопления, были ли они удачными или нет. Организованна программа очень просто, при старте вы попадаете в список доступных целей, в которых цветом отмечен статус
* красный цвет означает, что цель не была достигнута в течение заданного промежутка времени
* золотой цвет означает, что в течение заданного времени цель была достигнута
* зелёный цвет означает, что время ещё не вышло

Далее, выбирая нужную цель или создав новую нажатием на кнопку “+” вы попадаете в окно управления целью. В этом окне можно изменить саму цель, добавить новые начисления (или списания) или изменить предыдущие записи. При этом в окошке сверху будет показано сколько уже набрано, сколько ещё осталось набрать, сколько времени прошло и сколько осталось. Для удобства, та же информация отображается в виде прогресс-баров. Если прогресс бар набранных денег хотя бы приблизительно совпадает или опережает прогресс прошедшего времени, то значит всё у вас хорошо и есть хороший шанс набрать деньги в срок. Если же он отстаёт, то значит надо задуматься над тем, откуда взять недостающую сумму и может быть пришла пора немного поэкономить.

Ну и для тех, кто не любит избыток информации, при простом нажатии на центральный экран он сворачивается в минимальный режим.