Java android data model

Room: Хранение данных на Android для всех и каждого

Room — это новый способ сохранить данные приложений в Android-приложении, представленный в этом году на Google I/O. Это часть новойAndroid Architecture, группа библиотек от Google, которые поддерживают уместную архитектуру приложений. Room предлагается в качестве альтернативы Realm, ORMLite, GreenDao и многим другим.

Room — это высокоуровневый интерфейс для низкоуровневых привязок SQLite, встроенных в Android, о которых вы можете узнать больше в документации. Он выполняет большую часть своей работы во время компиляции, создавая API-интерфейс поверх встроенного SQLite API, поэтому вам не нужно работать с Cursor или ContentResolver.

Использование Room

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

Чтобы рассказать Room о классе Person, добавляем аннотицию Entity к классу и @PrimaryKey к ключу:

@Entity public class Person

Благодаря этим двум аннотациям Room теперь знает, как создать таблицу для хранения экземпляров Person.

Важная вещь, которую следует учитывать при настройке ваших моделей: каждое поле, которое хранится в базе данных, должно быть общедоступным или иметь геттер и сеттер в стандартном стиле Java Beans (например, getName () и setName (имя строки)).

В классе Person теперь есть вся информация, которая требуется Room для создания таблиц, но у вас нет способа фактически добавлять, запрашивать или удалять данные из базы данных. Вот почему вам нужно будет сделать объект доступа к данным (DAO). DAO предоставляет интерфейс в самой базе данных и занимается манипулированием хранимыми данными Person.

Вот простой интерфейс DAO для класса Person:

@Dao public interface PersonDao < // Добавление Person в бд @Insert void insertAll(Person. people); // Удаление Person из бд @Delete void delete(Person person); // Получение всех Person из бд @Query("SELECT * FROM person") ListgetAllPeople(); // Получение всех Person из бд с условием @Query("SELECT * FROM person WHERE favoriteColor LIKE :color") List getAllPeopleWithFavoriteColor(String color); >

Первое, что нужно заметить, это то, что PersonDaoэто интерфейс, а не класс. Другая интересная деталь — это инструкции SQL в аннотациях Query (). Операторы SQL говорят Room, какую информацию вы хотите получить из базы данных. Они также проверяются во время компиляции. Поэтому, если вы измените подпись метода List getAllPeopleWithFavoriteColor ( название цвета ) на List getAllPeopleWithFavoriteColor ( int color ), Room выдаст ошибку во время компиляции:

incompatible types: int cannot be converted to String

И если вы сделаете опечатку в выражении SQL, например, напишите favoriteColors ( множественное число ) вместо favoriteColor ( единственное число ), Room также выдаст ошибку компиляции:

There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such column: favoriteColors)

Вы не можете получить экземпляр PersonDao, потому что это интерфейс. Чтобы иметь возможность использовать классы DAO, вам необходимо создать класс базы данных. За кулисами этот класс будет отвечать за ведение самой базы данных и предоставление экземпляров DAO.

Вы можете создать свой класс базы данных всего за пару строк:

@Database(entities = , version = 1) public abstract class AppDatabase extends RoomDatabase

Это лишь описание структуры базы данных, но сама база данных будет жить в одном файле. Чтобы получить экземпляр AppDatabase, сохраненный в файле с именем populus-database, вы должны написать:

AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "populus-database").build();

Если вы хотите получить все данные обо всех Person, которые находятся в базе данных, вы могли бы написать:

List everyone = db.getPersonDao().getAllPeople();

Преимущества использования Room

В отличие от большинства ORM, Room использует обработчик аннотации для выполнения всей своей манеры сохранения данных. Это означает, что ни ваши классы приложений, ни классы моделей не должны ничего расширять в Room, в отличие от многих других ORM, включая Realm и SugarORM. Как вы видели при ошибках с аннотациями Query () выше, вы также получаете возможность проверки корректности SQL-запросов во время компиляции, что может сэкономить вам много хлопот.

Читайте также:  Python str format with

Room также позволяет вам наблюдать за изменениями данных, интегрируя их как с API LiveData Архитектурных Компонентов, так и с RxJava 2. Это означает, что если у вас сложная схема, где изменения в базе данных должны появляться в нескольких местах вашего приложения, Room делает уведомления об изменениях. Это мощное дополнение может быть включено одной строкой. Все, что вам нужно сделать, это изменить тип возвращаемых значений.

@Query("SELECT * FROM person") List getAllPeople();
@Query("SELECT * FROM person") LiveData> /* or Observable> */ getAllPeople();

Самое большое ограничение в Room: взаимосвязи

Самым большим ограничением в Room является то, что он не будет обрабатывать отношения с другими типами сущностей для вас автоматически, как и другие ORM. Это означает, что если вы хотите отслеживать домашних животных:

@Entity public class Person < @PrimaryKey String name; int age; String favoriteColor; Listpets; > @Entity public class Pet

То Room выдаст ошибку компиляци, так как не знает, как сохранить отношения между Person и Pet:

Cannot figure out how to save this field into database. You can consider adding a type converter for it.

Ошибка при компиляции предлагает конвертер типов, который преобразует объекты в примитивы, которые могут быть непосредственно сохранены в SQL. Поскольку List нельзя свести к примитиву, вам нужно сделать что-то другое. Это отношения «один ко многим», где у одного Person может быть много Pet. Room не может моделировать такие отношения, но она может справиться с обратными отношениями — у каждого Pet есть один Person. Чтобы смоделировать это, удалите поле для Pet в Person и добавьте поле ownerId в класс Pet:

@Entity public class Person < @PrimaryKey String name; int age; String favoriteColor; >@Entity(foreignKeys = @ForeignKey( entity = Person.class, parentColumns = "name", childColumns = "ownerId")) public class Pet < @PrimaryKey String name; String breed; String ownerId; // this ID points to a Person >

Это приведет к тому, что Room обеспечит ограничение внешнего ключа между объектами. Room не будет вызывать отношения «один-ко-многим» и «много-к-одному», но она дает вам инструменты для выражения этих отношений.

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

@Query("SELECT * FROM pet WHERE ownderId IS :ownerId") List getPetsForOwner(String ownerId);

Стоит ли использовать Room?

Если вы уже настроили сохранение данных в своем приложении и довольны им, то ничего не изменяйте. Каждая ORM и встроенная реализация SQLite будут продолжать работать так же, как и раньше. Room — это всего лишь еще один вариант сохранения данных.

Читайте также:  Yandex team ru php

Если вы используете SQLite или собираетесь использовать его, вы должны попробовать Room. Он обладает всеми возможностями, необходимыми для выполнения расширенных запросов, одновременно устраняя необходимость писать SQL-запросы для поддержки базы данных самостоятельно.

Источник

Java android data model

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

Так, создадим новый проект с пустой MainActivity и прежде всего добавим в него класс модели, который назовем User :

package com.example.databaseadapterapp; public class User < private long id; private String name; private int year; User(long id, String name, int year)< this.id = id; this.name = name; this.year = year; >public long getId() < return id; >public String getName() < return name; >public void setName(String name) < this.name = name; >public int getYear() < return year; >public void setYear(int year) < this.year = year; >@Override public String toString() < return this.name + " : " + this.year; >>

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

Для взаимодействия с базой данных SQLite добавим новый класс DatabaseHelper :

package com.example.databaseadapterapp; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteDatabase; import android.content.Context; public class DatabaseHelper extends SQLiteOpenHelper < private static final String DATABASE_NAME = "userstore.db"; // название бд private static final int SCHEMA = 1; // версия базы данных static final String TABLE = "users"; // название таблицы в бд // названия столбцов public static final String COLUMN_ID = "_id"; public static final String COLUMN_NAME = "name"; public static final String COLUMN_YEAR = "year"; public DatabaseHelper(Context context) < super(context, DATABASE_NAME, null, SCHEMA); >@Override public void onCreate(SQLiteDatabase db) < db.execSQL("CREATE TABLE " + TABLE + " (" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_NAME + " TEXT, " + COLUMN_YEAR + " INTEGER);"); // добавление начальных данных db.execSQL("INSERT INTO "+ TABLE +" (" + COLUMN_NAME + ", " + COLUMN_YEAR + ") VALUES ('Том Смит', 1981);"); >@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) < db.execSQL("DROP TABLE IF EXISTS "+TABLE); onCreate(db); >>

Также для работы с базой данных добавим в проект класс DatabaseAdapter :

package com.example.databaseadapterapp; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import java.util.ArrayList; import java.util.List; public class DatabaseAdapter < private DatabaseHelper dbHelper; private SQLiteDatabase database; public DatabaseAdapter(Context context)< dbHelper = new DatabaseHelper(context.getApplicationContext()); >public DatabaseAdapter open() < database = dbHelper.getWritableDatabase(); return this; >public void close() < dbHelper.close(); >private Cursor getAllEntries()< String[] columns = new String[] ; return database.query(DatabaseHelper.TABLE, columns, null, null, null, null, null); > public List getUsers() < ArrayListusers = new ArrayList<>(); Cursor cursor = getAllEntries(); while (cursor.moveToNext()) < int String name = cursor.getString(cursor.getColumnIndex(DatabaseHelper.COLUMN_NAME)); int year = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.COLUMN_YEAR)); users.add(new User(id, name, year)); >cursor.close(); return users; > public long getCount() < return DatabaseUtils.queryNumEntries(database, DatabaseHelper.TABLE); >public User getUser(long id)< User user = null; String query = String.format("SELECT * FROM %s WHERE %s=?",DatabaseHelper.TABLE, DatabaseHelper.COLUMN_ID); Cursor cursor = database.rawQuery(query, new String[]< String.valueOf(id)>); if(cursor.moveToFirst()) < String name = cursor.getString(cursor.getColumnIndex(DatabaseHelper.COLUMN_NAME)); int year = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.COLUMN_YEAR)); user = new User(id, name, year); >cursor.close(); return user; > public long insert(User user) < ContentValues cv = new ContentValues(); cv.put(DatabaseHelper.COLUMN_NAME, user.getName()); cv.put(DatabaseHelper.COLUMN_YEAR, user.getYear()); return database.insert(DatabaseHelper.TABLE, null, cv); >public long delete(long userId)< String whereClause = "_id = ?"; String[] whereArgs = new String[]; return database.delete(DatabaseHelper.TABLE, whereClause, whereArgs); > public long update(User user)< String whereClause = DatabaseHelper.COLUMN_ID + " b">UserActivity. В итоге весь проект будет выглядеть следующим образом:

Модель и репозиторий в Android и Java

В файле activity_user.xml в папке res/layout определим для UserActivity простейший интерфейс:

       

В классе UserActivity опредлим логику добавления/изменения/удаления пользователя:

package com.example.databaseadapterapp; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; public class UserActivity extends AppCompatActivity < private EditText nameBox; private EditText yearBox; private Button delButton; private DatabaseAdapter adapter; private long userId=0; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_user); nameBox = findViewById(R.id.name); yearBox = findViewById(R.id.year); delButton = findViewById(R.id.deleteButton); adapter = new DatabaseAdapter(this); Bundle extras = getIntent().getExtras(); if (extras != null) < userId = extras.getLong("id"); >// если 0, то добавление if (userId > 0) < // получаем элемент по id из бд adapter.open(); User user = adapter.getUser(userId); nameBox.setText(user.getName()); yearBox.setText(String.valueOf(user.getYear())); adapter.close(); >else < // скрываем кнопку удаления delButton.setVisibility(View.GONE); >> public void save(View view) < String name = nameBox.getText().toString(); int year = Integer.parseInt(yearBox.getText().toString()); User user = new User(userId, name, year); adapter.open(); if (userId >0) < adapter.update(user); >else < adapter.insert(user); >adapter.close(); goHome(); > public void delete(View view) < adapter.open(); adapter.delete(userId); adapter.close(); goHome(); >private void goHome() < // переход к главной activity Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(intent); >>

Эта activity используется для добавления/редактирования/удаления одного объекта User. Если в UserActivity передается параметр id, то значит мы находимся в режиме редактирования пользователя, поэтому обращаемся к методу getUser() класса DatabaseAdapter для получения нужного пользователя.

Для добавления/изменения/удаления пользователя по нажатию на кнопку вызывается соответствующий метод класса DatabaseAdapter.

В файле activity_main.xml в папке res/layout определим визуальный интерфейс для MainActivity:

Здесь имеется элемент ListView для вывода объектов из таблицы и кнопка для перехода к UserActivity для добавления пользователя.

И изменим код MainActivity :

package com.example.databaseadapterapp; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import java.util.List; public class MainActivity extends AppCompatActivity < private ListView userList; ArrayAdapterarrayAdapter; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); userList = findViewById(R.id.list); userList.setOnItemClickListener(new AdapterView.OnItemClickListener() < @Override public void onItemClick(AdapterViewparent, View view, int position, long id) < User user =arrayAdapter.getItem(position); if(user!=null) < Intent intent = new Intent(getApplicationContext(), UserActivity.class); intent.putExtra("id", user.getId()); startActivity(intent); >> >); > @Override public void onResume() < super.onResume(); DatabaseAdapter adapter = new DatabaseAdapter(this); adapter.open(); Listusers = adapter.getUsers(); arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, users); userList.setAdapter(arrayAdapter); adapter.close(); > // по нажатию на кнопку запускаем UserActivity для добавления данных public void add(View view) < Intent intent = new Intent(this, UserActivity.class); startActivity(intent); >>

В переопределенном методе onResume() через объект DatabaseAdapter получаем всех пользователей из базы данных и через ArrayAdapter выводим их в ListView.

При нажатии на элемент ListView запускаем UserActivity, передавая ей id выделенного пользователя.

При нажатии на кнопку просто вызываем UserActivity.

При запуске MainActivity отобразит список пользователей из базы данных, а при переходе к UserActivity мы сможем подредактировать или добавить пользователей:

Источник

Оцените статью