В прошлых темах было рассмотрено взаимодействие с базой данных через класс 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[] {DatabaseHelper.COLUMN_ID, DatabaseHelper.COLUMN_NAME, DatabaseHelper.COLUMN_YEAR};
return database.query(DatabaseHelper.TABLE, columns, null, null, null, null, null);
}
public List<User> getUsers(){
ArrayList<User> users = new ArrayList<>();
Cursor cursor = getAllEntries();
while (cursor.moveToNext()){
int id = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.COLUMN_ID));
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[]{String.valueOf(userId)};
return database.delete(DatabaseHelper.TABLE, whereClause, whereArgs);
}
public long update(User user){
String whereClause = DatabaseHelper.COLUMN_ID + "=" + user.getId();
ContentValues cv = new ContentValues();
cv.put(DatabaseHelper.COLUMN_NAME, user.getName());
cv.put(DatabaseHelper.COLUMN_YEAR, user.getYear());
return database.update(DatabaseHelper.TABLE, cv, whereClause, null);
}
}
Фактически данный класс выполняет роль репозитория данных. Чтобы взамодействовать с БД он определяет методы open() и close(),
которые соответственно открывают и закрывают подключение к базе данных.
Непосредственно для работы с данными в классе определены методы insert() (добавление), delete() (удаление),
update() (обновление), getUsers() (получение всех пользователей из таблицы) и getUser() (получение одного пользователя по id).
В качестве пользовательского интерфейса будем отталкиваться от того функционала, который использовался в прошлых темах. Так, добавим в проект новый класс Activity - UserActivity. В итоге весь проект будет выглядеть следующим образом:
В файле activity_user.xml в папке res/layout определим для UserActivity простейший интерфейс:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="Введите имя"
app:layout_constraintBottom_toTopOf="@+id/year"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<EditText
android:id="@+id/year"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="Введите год рождения"
app:layout_constraintTop_toBottomOf="@+id/name"
app:layout_constraintBottom_toTopOf="@+id/saveButton"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<Button
android:id="@+id/saveButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Сохранить"
android:onClick="save"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintTop_toBottomOf="@+id/year"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/deleteButton"
/>
<Button
android:id="@+id/deleteButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Удалить"
android:onClick="delete"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintTop_toBottomOf="@+id/year"
app:layout_constraintLeft_toRightOf="@+id/saveButton"
app:layout_constraintRight_toRightOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
В классе 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:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/addButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Добавить"
android:onClick="add"
app:layout_constraintBottom_toTopOf="@+id/list"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<ListView
android:id="@+id/list"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/addButton"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Здесь имеется элемент 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;
ArrayAdapter<User> arrayAdapter;
@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(AdapterView<?> parent, 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();
List<User> users = 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 мы сможем подредактировать или добавить пользователей: