Last active
November 21, 2025 14:02
-
-
Save sunmeat/b3cb8e635f1050e28d70186ca389d54e to your computer and use it in GitHub Desktop.
room database example android
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| settings.gradle.kts: | |
| pluginManagement { | |
| repositories { | |
| gradlePluginPortal() // обов’язково поставити зверху! тут лежить kotlin("android") | |
| google { | |
| content { | |
| includeGroupByRegex("com\\.android.*") | |
| includeGroupByRegex("com\\.google.*") | |
| includeGroupByRegex("androidx.*") | |
| } | |
| } | |
| mavenCentral() | |
| } | |
| } | |
| dependencyResolutionManagement { | |
| repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) | |
| repositories { | |
| google() | |
| mavenCentral() | |
| } | |
| } | |
| rootProject.name = "StudentRoom" | |
| include(":app") | |
| ============================================================================================================ | |
| build.gradle.kts: | |
| plugins { | |
| alias(libs.plugins.android.application) | |
| kotlin("android") version "2.1.20" // !!! https://kotlinlang.org/docs/whatsnew2120.html | |
| kotlin("kapt") version "2.1.20" // !!! плагін Gradle, який потрібен, щоб обробляти анотації в Kotlin-коді | |
| } | |
| android { | |
| namespace = "site.sunmeat.helloworld" | |
| compileSdk = 36 | |
| defaultConfig { | |
| applicationId = "site.sunmeat.helloworld" | |
| minSdk = 33 | |
| targetSdk = 36 | |
| versionCode = 1 | |
| versionName = "1.0" | |
| } | |
| buildTypes { | |
| release { | |
| isMinifyEnabled = false | |
| proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") | |
| } | |
| } | |
| compileOptions { | |
| sourceCompatibility = JavaVersion.VERSION_17 | |
| targetCompatibility = JavaVersion.VERSION_17 | |
| } | |
| kotlinOptions { | |
| jvmTarget = "17" // !!! | |
| } | |
| buildFeatures { | |
| viewBinding = true // !!! | |
| } | |
| } | |
| dependencies { | |
| implementation("androidx.core:core-ktx:1.13.1") | |
| implementation("androidx.appcompat:appcompat:1.7.1") | |
| implementation("androidx.activity:activity:1.9.3") | |
| implementation("androidx.constraintlayout:constraintlayout:2.2.1") // https://developer.android.com/jetpack/androidx/releases/constraintlayout | |
| implementation("androidx.cardview:cardview:1.0.0") | |
| implementation("androidx.recyclerview:recyclerview:1.4.0") // https://developer.android.com/jetpack/androidx/releases/recyclerview | |
| implementation("com.google.android.material:material:1.12.0") | |
| // Room | |
| val roomVersion = "2.8.3" // https://developer.android.com/jetpack/androidx/releases/room | |
| implementation("androidx.room:room-runtime:$roomVersion") | |
| kapt("androidx.room:room-compiler:$roomVersion") | |
| implementation("androidx.room:room-ktx:$roomVersion") | |
| // Lifecycle | |
| implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.4") // https://developer.android.com/jetpack/androidx/releases/lifecycle | |
| implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.9.4") | |
| } | |
| ============================================================================================================ | |
| MainActivity.java: | |
| package site.sunmeat.helloworld; | |
| import android.os.Bundle; | |
| import android.widget.*; | |
| import androidx.appcompat.app.AppCompatActivity; | |
| import androidx.lifecycle.ViewModelProvider; | |
| import androidx.recyclerview.widget.*; | |
| import androidx.annotation.NonNull; | |
| import androidx.lifecycle.*; | |
| import androidx.room.*; | |
| import java.util.*; | |
| // ======================== ROOM КЛАСИ ======================== | |
| @Entity(tableName = "students") | |
| class Student { | |
| @PrimaryKey(autoGenerate = true) | |
| public long _id; // для майбутнього контент резолвера з його курсорами бажано поставити саме тип лонг + _ для поля айді | |
| public String firstName; | |
| public String lastName; | |
| public int age; | |
| public Student() {} | |
| public Student(String firstName, String lastName, int age) { | |
| this.firstName = firstName; | |
| this.lastName = lastName; | |
| this.age = age; | |
| } | |
| @NonNull | |
| @Override | |
| public String toString() { | |
| return firstName + " " + lastName + ", вік: " + age; | |
| } | |
| } | |
| @Dao // DAO (Data Access Object) - це інтерфейс, який відповідає за всі операції з базою даних | |
| // для таблиці "students". Room автоматично згенерує реалізацію цього інтерфейсу під час компіляції | |
| interface StudentDao { | |
| @Insert void insert(Student student); | |
| @Query("SELECT * FROM students ORDER BY lastName") LiveData<List<Student>> getAllStudents(); // клас з Android Architecture Components, | |
| // який дозволяє спостерігати за даними і автоматично оновлювати UI, коли вони змінюються | |
| @Query("DELETE FROM students") void deleteAll(); | |
| } | |
| @Database(entities = {Student.class}, version = 1, exportSchema = false) | |
| abstract class AppDatabase extends RoomDatabase { | |
| abstract StudentDao studentDao(); | |
| private static volatile AppDatabase INSTANCE; | |
| static AppDatabase getDatabase(final android.content.Context context) { | |
| if (INSTANCE == null) { | |
| synchronized (AppDatabase.class) { | |
| if (INSTANCE == null) { | |
| INSTANCE = Room.databaseBuilder(context.getApplicationContext(), | |
| AppDatabase.class, "student_database").build(); | |
| // Room працює саме з SQLite - це не окрема БД, а зручна надбудова (обгортка) над класичною Android-базою SQLite | |
| } | |
| } | |
| } | |
| return INSTANCE; | |
| } | |
| } | |
| class StudentRepository { | |
| private final StudentDao dao; | |
| private final LiveData<List<Student>> allStudents; | |
| StudentRepository(android.app.Application app) { | |
| AppDatabase db = AppDatabase.getDatabase(app); | |
| dao = db.studentDao(); | |
| allStudents = dao.getAllStudents(); | |
| } | |
| LiveData<List<Student>> getAllStudents() { return allStudents; } | |
| void insert(Student s) { new Thread(() -> dao.insert(s)).start(); } | |
| void deleteAll() { new Thread(dao::deleteAll).start(); } | |
| } | |
| class StudentAdapter extends RecyclerView.Adapter<StudentAdapter.VH> { | |
| private List<Student> data = new ArrayList<>(); | |
| void setStudents(List<Student> list) { | |
| data = list; | |
| notifyDataSetChanged(); | |
| } | |
| @NonNull | |
| @Override | |
| public VH onCreateViewHolder(@NonNull android.view.ViewGroup parent, int viewType) { | |
| android.view.View v = android.view.LayoutInflater.from(parent.getContext()) | |
| .inflate(android.R.layout.simple_list_item_1, parent, false); | |
| return new VH(v); | |
| } | |
| @Override | |
| public void onBindViewHolder(@NonNull VH holder, int pos) { | |
| holder.tv.setText(data.get(pos).toString()); | |
| } | |
| @Override | |
| public int getItemCount() { return data.size(); } | |
| static class VH extends RecyclerView.ViewHolder { | |
| android.widget.TextView tv; | |
| VH(android.view.View v) { super(v); tv = v.findViewById(android.R.id.text1); } | |
| } | |
| } | |
| public class MainActivity extends AppCompatActivity { | |
| // в ідеалі, звісно, всі ці класи треба рознести по окремим файлам | |
| public static class StudentViewModel extends AndroidViewModel { | |
| private final StudentRepository repo; | |
| private final LiveData<List<Student>> allStudents; | |
| public StudentViewModel(android.app.Application app) { | |
| super(app); | |
| repo = new StudentRepository(app); | |
| allStudents = repo.getAllStudents(); | |
| } | |
| public LiveData<List<Student>> getAllStudents() { return allStudents; } | |
| public void insert(Student s) { repo.insert(s); } | |
| public void deleteAll() { repo.deleteAll(); } | |
| } | |
| private StudentViewModel viewModel; | |
| private final StudentAdapter adapter = new StudentAdapter(); | |
| @Override | |
| protected void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| setContentView(R.layout.activity_main); | |
| EditText etFirstName = findViewById(R.id.etFirstName); | |
| EditText etLastName = findViewById(R.id.etLastName); | |
| EditText etAge = findViewById(R.id.etAge); | |
| Button btnAdd = findViewById(R.id.btnAdd); | |
| Button btnClear = findViewById(R.id.btnClear); | |
| RecyclerView rv = findViewById(R.id.recyclerView); | |
| rv.setLayoutManager(new LinearLayoutManager(this)); | |
| rv.setAdapter(adapter); | |
| // отримуємо ViewModel, який має доступ до Application (потрібно для Room) | |
| // без другого параметра (фабрики) крошиться, бо AndroidViewModel вимагає Application у конструкторі | |
| viewModel = new ViewModelProvider( | |
| this, | |
| ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()) | |
| ).get(StudentViewModel.class); | |
| viewModel.getAllStudents().observe(this, adapter::setStudents); | |
| btnAdd.setOnClickListener(v -> { | |
| String fn = etFirstName.getText().toString().trim(); | |
| String ln = etLastName.getText().toString().trim(); | |
| String ageStr = etAge.getText().toString().trim(); | |
| if (!fn.isEmpty() && !ln.isEmpty() && !ageStr.isEmpty()) { | |
| int age = Integer.parseInt(ageStr); | |
| viewModel.insert(new Student(fn, ln, age)); | |
| etFirstName.setText(""); | |
| etLastName.setText(""); | |
| etAge.setText(""); | |
| } | |
| }); | |
| btnClear.setOnClickListener(v -> viewModel.deleteAll()); | |
| } | |
| } | |
| ============================================================================================================ | |
| activity_main.xml: | |
| <?xml version="1.0" encoding="utf-8"?> | |
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
| android:layout_width="match_parent" | |
| android:layout_height="match_parent" | |
| android:background="#F5F5F5" | |
| android:orientation="vertical" | |
| android:padding="20dp"> | |
| <TextView | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:layout_marginBottom="20dp" | |
| android:gravity="center" | |
| android:text="База студентів" | |
| android:textColor="#1976D2" | |
| android:textSize="26sp" | |
| android:textStyle="bold" /> | |
| <EditText | |
| android:id="@+id/etFirstName" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:layout_marginBottom="8dp" | |
| android:background="@android:drawable/editbox_background_normal" | |
| android:hint="Ім'я" | |
| android:padding="12dp" /> | |
| <EditText | |
| android:id="@+id/etLastName" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:layout_marginBottom="8dp" | |
| android:background="@android:drawable/editbox_background_normal" | |
| android:hint="Прізвище" | |
| android:padding="12dp" /> | |
| <EditText | |
| android:id="@+id/etAge" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:layout_marginBottom="16dp" | |
| android:background="@android:drawable/editbox_background_normal" | |
| android:hint="Вік" | |
| android:inputType="number" | |
| android:padding="12dp" /> | |
| <LinearLayout | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:orientation="horizontal"> | |
| <Button | |
| android:id="@+id/btnAdd" | |
| android:layout_width="0dp" | |
| android:layout_height="wrap_content" | |
| android:layout_marginEnd="8dp" | |
| android:layout_weight="1" | |
| android:backgroundTint="#4CAF50" | |
| android:text="Додати" /> | |
| <Button | |
| android:id="@+id/btnClear" | |
| android:layout_width="0dp" | |
| android:layout_height="wrap_content" | |
| android:layout_weight="1" | |
| android:backgroundTint="#F44336" | |
| android:text="Очистити" /> | |
| </LinearLayout> | |
| <TextView | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:layout_marginTop="24dp" | |
| android:layout_marginBottom="8dp" | |
| android:text="Список студентів" | |
| android:textSize="18sp" | |
| android:textStyle="bold" /> | |
| <androidx.recyclerview.widget.RecyclerView | |
| android:id="@+id/recyclerView" | |
| android:layout_width="match_parent" | |
| android:layout_height="0dp" | |
| android:layout_weight="1" | |
| android:background="#FFFFFF" | |
| android:clipToPadding="false" | |
| android:padding="8dp" | |
| android:scrollbars="vertical" /> | |
| </LinearLayout> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment