Как стать автором
Обновить

Использование key-value базы данных Snappy в Android

Время на прочтение6 мин
Количество просмотров2.7K
SnappyDB — NoSQL key-value база данных для Android. Она довольно проста в использовании и является неплохим вариантом, если вы хотите использовать NoSQL вариант базы данных в своём проекте (подробнее тут).
По заявлениям разработчиков, в операциях записи и чтения Snappy превосходит по скорости SQLite:

image

Итак, начнём. Для начала необходимо добавить dependencies в build.gradle:

implementation 'com.snappydb:snappydb-lib:0.5.2'
implementation 'com.esotericsoftware.kryo:kryo:2.24.0'


Теперь начнём, непосредственно, работу с самой БД.
Для начала разберёмся, как при помощи SnappyDB работать с примитивными типами и массивами, сохранять и получать их.
Для наглядности создадим небольшую разметку:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/filmNameTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="25sp"
        android:layout_centerInParent="true"
        android:layout_margin="8dp"
        />

    <TextView
        android:id="@+id/filmBudgetTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textSize="25sp"
        android:layout_below="@+id/filmNameTextView"
        android:layout_margin="8dp"
        />

    <TextView
        android:id="@+id/genreTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textSize="25sp"
        android:layout_below="@id/filmBudgetTextView"
        android:layout_margin="8dp"
        />

    <TextView
        android:id="@+id/isAdult"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/genreTextView"
        android:textSize="25sp"
        android:layout_centerInParent="true"
        />
</RelativeLayout>

Допустим, что мы будем хранить в нашей БД данные о фильме

В MainActivity создадим метод PutValues:
private void putValues(String name, int budget, boolean isAdult, String[] genres) throws SnappydbException {
        DB snappyDB = DBFactory.open(this,"Film");
        // создание БД с именем Film (для создания новой также используется метод open)

        snappyDB.put("Name", name);
        snappyDB.putInt("budget", budget);
        snappyDB.putBoolean("isAdult", isAdult);
        snappyDB.put("genres", genres);
        //кладём в БД данные в зависимости от типа
}

Заметьте, что метод, в котором мы работаем со SnappyDB должен выбрасывать исключение SnappydbException.

Теперь напишем метод setValues для получения данных из БД и их вывода:
private void setValues(DB snappyDB) throws SnappydbException {
        TextView filmNameTextView = findViewById(R.id.filmNameTextView),
                 filmBudgetTextView = findViewById(R.id.filmBudgetTextView),
                 genresTextView = findViewById(R.id.genreTextView),
                 isAdultTextView = findViewById(R.id.isAdult); //поля из созданной ранее разметки

        String name = snappyDB.get("Name");
        int budget = snappyDB.getInt("budget");
        boolean isAdult = snappyDB.getBoolean("isAdult");
        String[] genres = snappyDB.getObjectArray("genres", String.class);//2 параметр = имя класса
        // метод get... в зависимости от типа данных

        filmNameTextView.setText(name);
        filmBudgetTextView.setText(String.valueOf(budget));
        isAdultTextView.setText(String.valueOf(isAdult));

        for(int i = 0;i < genres.length;i++) {
            genresTextView.setText(genresTextView.getText() + " " + genres[i]);
        }
}


Вызовем созданные методы в onCreate (обязательно окружив их блоком try/catch):
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        try {
            putValues("Forrest Gump", 677000000,false, new String[] {"Drama","Melodrama"});
        } catch (SnappydbException e) {
            e.printStackTrace();
        }
        
        try {
            DB snappyDB = DBFactory.open(this, "Film");
            setValues(snappyDB);
        } catch (SnappydbException e) {
            e.printStackTrace();
        }
}


Запускаем и видим, что всё работает исправно:
image

А теперь разберёмся, как работать с собственными классами и другими сложными типами.
Создадим класс Film с 3 полями:
public class Film {
    private String name;
    private int budget;
    private String[] genres;

    public Film() {}

    public Film(String name, int budget, String[] genres) {
        this.name = name;
        this.budget = budget;
        this.genres = genres;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getBudget() {
        return budget;
    }

    public void setBudget(int budget) {
        this.budget = budget;
    }

    public String[] getGenres() {
        return genres;
    }

    public void setGenres(String[] genres) {
        this.genres = genres;
    }
}

Уберём вызовы методов setValues и putValues в onCreate. Создадим в нём новый объект класса Film и добавим его в БД:
Film film = new Film("Shawshank redemption",28000000, new String[] {"Drama"});
try {
       DB snappyDB = DBFactory.open(this, "NewFilmDB");
       snappyDB.put("FilmObj",film);
} catch (SnappydbException e) {
       e.printStackTrace();
}


Переработаем метод setValues:
private void setValues(DB snappyDB) throws SnappydbException {
        TextView filmNameTextView = findViewById(R.id.filmNameTextView),
                 filmBudgetTextView = findViewById(R.id.filmBudgetTextView),
                 genresTextView = findViewById(R.id.genreTextView);

        Film film = snappyDB.getObject("FilmObj", Film.class);
        
        String name = film.getName();
        int budget = film.getBudget();
        String[] genres = film.getGenres();

        filmNameTextView.setText(name);
        filmBudgetTextView.setText(String.valueOf(budget));

        for(int i = 0;i < genres.length;i++) {
            genresTextView.setText(genresTextView.getText() + " " + genres[i]);
        }
}

Вновь вызовем setValues в onCreate:
try {
        DB snappyDB = DBFactory.open(this, "NewFilmDB");
        setValues(snappyDB);
} catch (SnappydbException e) {
        e.printStackTrace();
}

Запускаем и видим, что всё работает:
image

Теперь давайте рассмотрим ещё несколько интересных функций SnappyDB:
1) Возможность искать ключи по префиксу:
Film film1 = new Film("Green mile",60000000,new String[] {"Drama", "Fantasy"}),
  film2 = new Film("Gentlemen",22000000,new String[] {"Comedy", "Crime"}),
  film3 = new Film("In Bruges",15000000,new String[] {"Comedy", "Crime", "Thriller"});

        try {
            DB snappyDB = DBFactory.open(this, "NewFilmDB");
            snappyDB.put("FilmObj: Green Mile",film1);
            snappyDB.put("FilmObj: Gentlemen",film2);
            snappyDB.put("FilmObj: In Bruges",film3);
            String[] filmKeys = snappyDB.findKeys("FilmObj:");
            //помещаем в массив filmKeys ключи с префиксом "FilmObj:"
            //если по одному ключу помещаются несколько значений, рассматривается последний добавленный
            for(int i = 0;i < filmKeys.length;i++) {
                Log.d("film_key: ",  filmKeys[i] + "\n");
            }

            Log.d("film_name: ",  snappyDB.getObject(filmKeys[2],Film.class).getName() + "\n");
            //выводим эл-т по ключу, взятому из массива filmKeys

        } catch (SnappydbException e) {
            e.printStackTrace();
 }

image
Вывод в лог

2) Итерация по БД:
try {

            DB snappyDB = DBFactory.open(this, "NewFilmDB");

            for (String[] batch : snappyDB.allKeysIterator().byBatch(1)) {
                //итераторы работают с пакетами ключей(batch), а не с самими ключами
                for (String key : batch) {
                    Log.d("film",snappyDB.getObject(key,Film.class).getName());
                }
            }
        } catch (SnappydbException e) {
            e.printStackTrace();
}

Без использования byBatch у вас будет только KeyIterator, который не реализует Iterator или Iterable, поэтому вы не можете использовать его в цикле.
byBatch (n) создает BatchIterable, который является Iterable и Iterator. По сути, он просто вызывает next (n) для KeyIterator, когда вы вызываете next () для него.
Но byBatch стоит использовать только при большом кол-ве данных. В ином случае стоит использовать findKeys/findKeysBetween.

3) Удаление элемента по ключу:
snappyDB.del("FilmObj: Gentlemen");

image
Элемент удалён
4) Закрытие и удаление БД:
snappyDB.close();
snappyDB.destroy();


5) Узнать, существует ли ключ в БД:
snappyDB.put("FilmObj: Gentlemen",new Film());
boolean isExist = snappyDB.exists("FilmObj: Gentlemen");// true
snappyDB.del("FilmObj: Gentlemen");
isExist = snappyDB.exists("FilmObj: Gentlemen");//false



Ну вот и всё. Вам решать, использовать ли эту БД в своих проектах. Она достаточно быстра и проста в использовании, но выбор за вами. Это далеко не единственная БД для Android. Возможно, для вашего проекта лучше подойдёт другая БД (Room, SQLite, Realm и т.д). Вариантов масса.

P.S: SnappyDB на GitHub (оф.документация там же).
Различия между SQL и NoSQL: 1, 2
SQL vs Key-Value DB
Теги:
Хабы:
Всего голосов 4: ↑4 и ↓0+4
Комментарии5

Публикации

Истории

Работа

Ближайшие события

27 августа – 7 октября
Премия digital-кейсов «Проксима»
МоскваОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн
10 – 11 октября
HR IT & Team Lead конференция «Битва за IT-таланты»
МоскваОнлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн