В прошлых темах было рассмотрено взаимодействие с базой данных через класс 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 мы сможем подредактировать или добавить пользователей: