Використання наявної БД SQLite
Крім створення нової бази даних ми також можемо використовувати вже наявну. Це може бути більш переважним, тому що в цьому випадку база даних додатка вже міститиме всю необхідну інформацію.
Візьмемо проєкт, створений у попередній темі, де ми мали MainActivity, що виводила список об'єктів, і UserActivity, що давала змогу додавати, редагувати та видаляти об'єкти з БД.

Для початку створимо базу даних SQLite. У цьому нам може допомогти такий інструмент як Sqlitebrowser. Він безкоштовний і доступний для різних операційних систем за адресою https://sqlitebrowser.org/. Хоча можна використовувати й інші способи для створення початкової БД. Краще - tableplus.
Sqlitebrowser представляє графічний інтерфейс для створення бази даних і визначення в ній усіх необхідних таблиць:
Як видно на скріншоті, я визначаю таблицю users із трьома полями: _id, name, age. Загальна команда на створення таблиці буде такою:
CREATE TABLE `users` (
`_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`name` TEXT NOT NULL,
`year` INTEGER NOT NULL
);
Там же в програмі додамо кілька елементів у створену таблицю:

Після створення таблиці додамо в проєкт в Android Studio папку assets, а в папку assets - щойно створену базу даних. Для цього перейдемо до повного визначення проєкту, натиснемо на папку main правою кнопкою миші і в меню виберемо New -> Directory:
Потім у віконці, що з'явилося, виберемо пункт src\main\assets і натиснемо на Enter для її додавання в проєкт:
І потім скопіюємо в неї нашу базу даних:
У моєму випадку база даних називається "cityinfo.db".
Змінимо код DatabaseHelper таким чином:
package com.example.sqliteapp;
import android.database.SQLException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.content.Context;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
class DatabaseHelper extends SQLiteOpenHelper {
private static String DB_PATH; // повний шлях до бази даних
private static String DB_NAME = "cityinfo.db";
private static final int SCHEMA = 1; // версія бази даних
static final String TABLE = "users"; // назва таблиці в бд
// назви стовпців
static final String COLUMN_ID = "_id";
static final String COLUMN_NAME = "name";
static final String COLUMN_YEAR = "year";
private Context myContext;
DatabaseHelper(Context context) {
super(context, DB_NAME, null, SCHEMA);
this.myContext=context;
DB_PATH =context.getFilesDir().getPath() + DB_NAME;
}
@Override
public void onCreate(SQLiteDatabase db) { }
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
void create_db(){
File file = new File(DB_PATH);
if (!file.exists()) {
// отримуємо локальну бд як потік
try(InputStream myInput = myContext.getAssets().open(DB_NAME);
// Відкриваємо порожню бд
OutputStream myOutput = new FileOutputStream(DB_PATH)) {
// побайтово копіюємо дані
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
}
catch(IOException ex){
Log.d("DatabaseHelper", ex.getMessage());
}
}
}
public SQLiteDatabase open()throws SQLException {
return SQLiteDatabase.openDatabase(DB_PATH, null, SQLiteDatabase.OPEN_READWRITE);
}
}
За замовчуванням база даних буде розміщуватися у зовнішньому сховищі, виділеному для додатку в папці /data/data/[назва_пакета]/databases/, і щоб отримати повний шлях до бази даних, у конструкторі використовується вираз:
DB_PATH = context.getFilesDir().getPath() + DB_NAME;
Метод onCreate() нам не потрібен, оскільки нам не потрібно створення вбудованої бази даних. Замість цього тут визначений додатковий метод create_db(), мета якого — копіювання бази даних з папки assets в те місце, яке вказано в змінній DB_PATH.
Окрім того, тут також визначений метод відкриття бази даних open() за допомогою методу SQLiteDatabase.openDatabase().
Новий спосіб організації підключення змінить використання DatabaseHelper в activity. Так, оновимо клас MainActivity:
package com.example.sqliteapp;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.SimpleCursorAdapter;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.widget.ListView;
public class MainActivity extends AppCompatActivity {
ListView userList;
DatabaseHelper databaseHelper;
SQLiteDatabase db;
Cursor userCursor;
SimpleCursorAdapter userAdapter;
@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) {
Intent intent = new Intent(getApplicationContext(), UserActivity.class);
intent.putExtra("id", id);
startActivity(intent);
}
});
databaseHelper = new DatabaseHelper(getApplicationContext());
// створюємо базу даних
databaseHelper.create_db();
}
@Override
public void onResume() {
super.onResume();
// відкриваємо підключення
db = databaseHelper.open();
// отримуємо дані з бд у вигляді курсора
userCursor = db.rawQuery("select * from " + DatabaseHelper.TABLE, null);
// визначаємо, які стовпці з курсору будуть виводитися в ListView
String[] headers = new String[]{DatabaseHelper.COLUMN_NAME, DatabaseHelper.COLUMN_YEAR};
// створюємо адаптер, передаємо в нього курсор
userAdapter = new SimpleCursorAdapter(this, android.R.layout.two_line_list_item,
userCursor, headers, new int[]{android.R.id.text1, android.R.id.text2}, 0);
userList.setAdapter(userAdapter);
}
// по нажатию на кнопку запускаем UserActivity для добавления данных
public void add(View view) {
Intent intent = new Intent(this, UserActivity.class);
startActivity(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
// Закрываем подключение и курсор
db.close();
userCursor.close();
}
}
І також змінимо клас UserActivity:
package com.example.sqliteapp;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class UserActivity extends AppCompatActivity {
EditText nameBox;
EditText yearBox;
Button delButton;
Button saveButton;
DatabaseHelper sqlHelper;
SQLiteDatabase db;
Cursor userCursor;
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);
saveButton = findViewById(R.id.saveButton);
sqlHelper = new DatabaseHelper(this);
db = sqlHelper.open();
Bundle extras = getIntent().getExtras();
if (extras != null) {
userId = extras.getLong("id");
}
// якщо 0, то додавання
if (userId > 0) {
// отримуємо елемент за id із бд
userCursor = db.rawQuery("select * from " + DatabaseHelper.TABLE + " where " +
DatabaseHelper.COLUMN_ID + "=?", new String[]{String.valueOf(userId)});
userCursor.moveToFirst();
nameBox.setText(userCursor.getString(1));
yearBox.setText(String.valueOf(userCursor.getInt(2)));
userCursor.close();
} else {
// приховуємо кнопку видалення
delButton.setVisibility(View.GONE);
}
}
public void save(View view){
ContentValues cv = new ContentValues();
cv.put(DatabaseHelper.COLUMN_NAME, nameBox.getText().toString());
cv.put(DatabaseHelper.COLUMN_YEAR, Integer.parseInt(yearBox.getText().toString()));
if (userId > 0) {
db.update(DatabaseHelper.TABLE, cv, DatabaseHelper.COLUMN_ID + "=" + userId, null);
} else {
db.insert(DatabaseHelper.TABLE, null, cv);
}
goHome();
}
public void delete(View view){
db.delete(DatabaseHelper.TABLE, "_id = ?", new String[]{String.valueOf(userId)});
goHome();
}
private void goHome(){
// закриваємо підключення
db.close();
// переход к главной activity
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
}
Уся інша робота з даними буде тією ж, щоб і в минулих темах:
