Pull to refresh

Как подружить SQLite андроида с языком, отличным от английского

Reading time 4 min
Views 16K

Здравствуй, дорогой читатель!
В этой статье я хочу затронуть проблему хранения кириллических данных в SQLite, попробовать разобраться с Android NDK, и вообще зажить прекрасной жизнью! Однако, с этого момента, считаю важными первые два пункта. О них и поговорим.

Известная проблема SQLite состоит в том, что он не любит никаких символов, кроме латинских, поэтому выполняется такое [1]:
SELECT "ы" LIKE "Ы";
0
SELECT "s" LIKE "S";
1


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


Android NDK


Чтобы расширить твой кругозор, дорогой читатель, а так же создать годные костыли, я предлагаю использовать Android NDK [2] (скачайте и распакуйте в доступную папку)

Немного скучного

Android NDK — это иструмент для компилирования C/C++ кода в нативный код платформы Android. Кроме того, предоставляются многие библиотеки Android, так что определенные интенсивные участки программы можно написать в C/C++, а затем использовать в Java.
NDK поддерживается начиная с Android 1.5, и в данный момент поддерживаются следующие архитектуры процессоров ARMv5TE (включая инструкции Thumb-1), ARMv7-A (включая инструкции Thumb-2 и VFPv3-D16, с опциональной поддержкой NEON/VFPv3-D32)
Будущие релизы обещают поддержку x86

Короче, воспользуемся же этим инструментом!

Итак...


Что мы будем делать? Будем объединять исходный код sqlite и icu.
Дабы не нагружать процесс поиском нужных библиотек и исходников, предлагается собранный комплект для компиляции, здесь [3]. Прошу прощения, если случайно включено что-то лишнее.
Если вас не интересует процесс компиляции, вы можете скачать скомпилированную библиотеку здесь [7], и пропустить несколько пунктов

Скачав файл, распаковываем, и размещаем это драгоценное в ваш проект
project/jni
Где project здесь и далее — полный пусть до проекта

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

common/Android.mk

Здесь описываются все исходные файлы, подключаемые в будущую библиотеку, различные флаги и параметры сборки

common/android_sqlite...

Эти файлы осуществляют андроидоподобный доступ к базе, а так же интерфейс для взаимодействия с базой из Java.
Обратите внимание на сигнатуры функций
void Java_biz_sneg_sqlite_SQLiteDatabase_closedb()

Чтобы успешно использовать нативные функции, нужно описать их в формате Java_имя_пакета_класс_имяФункции
Так же я включил функцию определения географического расстояния GEODISTANCE(x1, y1, x2, y2), потому что, лично мне, ее не хватало.
Теперь легко подключить свои нужные функции, будь то sin, cos или ваши экзотические

Компиляция и подключение библиотеки


Сначала опишу шаги для Windows, потому как решение в лоб не работает.
Делай раз! Скачиваем и устанавливаем Cygwin [6], при установке выбираем пакеты Devel для установки. И… временно удаляемся на сон или другие приятные дела, потому что это адски долго. Хотя, возможно, я просто выбрал неправильный сервер.
Делай два! Запускаем консоль Cygwin (просто консоль для других ОС) и переходив в директорию с проекта:
Windows:
$ cd /cygdrive/project/jni
Non-windows:
$ cd project/jni

Делай три! Запускаем NDK
Windows:
$ /cygdrive/ndk-path/ndk-build
Non-windows:
$ ndk-path/ndk-build


Где project — путь к вашему проекту, ndk-path — путь, куда вы распаковали NDK
Должен запуститься процесс компиляции:
...
Compile++ thumb : android_sqlite <= tmutfmt.cpp
Compile++ thumb : android_sqlite <= colldata.cpp
Compile++ thumb : android_sqlite <= bmsearch.cpp
Compile++ thumb : android_sqlite <= bms.cpp
Compile++ thumb : android_sqlite <= currpinf.cpp
Compile++ thumb : android_sqlite <= uspoof.cpp
Compile++ thumb : android_sqlite <= uspoof_impl.cpp
...

Если не запустился — сочувствую О_о

На выходе мы должны получить скомпилированную библиотеку, по пути project/libs/armeabi/libandroid_sqlite.so

Теперь нам нужно подключить библиотеку к проекту.
Во-первых, в главном Activity мы должны описать ее подключение
public class MainActivity extends TabActivity {
	static {
	    System.loadLibrary("android_sqlite");
	}
...
}


Далее, нам нужен код, который бы работал с нативной библиотекой, и его можно скачать здесь [4]

Как работать?


Как, как, сели и поехали!
Открываем базу
try 
{
	dataBase_ = new biz.sneg.sqlite.SQLiteDatabase(DB_NAME);		
}
catch (Exception e) {
	Log.wtf("Database", e);
}


Достаем данные как-нибудь так, или как вам нравится
try {
	biz.sneg.sqlite.SQLiteCursor cursor = 
		dataBase_.query("SELECT * FROM tablename WHERE rus_text_field LIKE ?", new Object[]{"ура%"});

	List<Map<String, String>> results = new ArrayList<Map<String,String>>();

	while (cursor.next())
	{
		final int columnCount = cursor.count();
		HashMap<String, String> currentMap;
		currentMap = new HashMap<String, String>();
		for (int i = 0; i < columnCount; i++) 
		{
			currentMap.put(cursor.columnName(i), cursor.stringValue(i));
		}
		results.add(currentMap);
	}
	cursor.dispose();
}
catch (Exception e) {
	Log.wtf("Database", e);
}


В общем, желаю удачи!

Автор идеи и сборки Николай Кудашов, инвайт можно прислать сюда drklo.2kb<известный_символ>gmail.com

Ссылки:
1. SQLite и полноценный UNICODE
2. Android NDK
3. Исходники для библиотеки
4. Исходники для java
5. SQLite
6. Cygwin
7. Скомпилированная библиотека
Tags:
Hubs:
+28
Comments 37
Comments Comments 37

Articles