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

от автора

SnapyDB — 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.

P.S: SnappyDB на GitHub (оф.документация там же).
Различия между SQL и NoSQL: 1, 2

ссылка на оригинал статьи https://habr.com/ru/post/497222/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *