1. 项目准备
1.1 创建新项目
- 打开 Android Studio
- 选择 “Start a new Android Studio project”
- 选择 “Empty Activity” 模板
- 设置项目名称(比方 “SQLiteDemo”)
- 选择语言(Kotlin 或 Java,本教程以 Kotlin 为例)
- 设置最低 API 级别(建议 API 21 或更高)
- 点击 “Finish” 完成项目创建
1.2 添加必要依赖
确保 build.gradle (Module: app) 中包含以下依赖:
- dependencies {
- implementation 'androidx.core:core-ktx:1.7.0'
- implementation 'androidx.appcompat:appcompat:1.4.1'
- implementation 'com.google.android.material:material:1.5.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
-
- // Room 数据库(SQLite 的抽象层)
- implementation "androidx.room:room-runtime:2.4.2"
- implementation "androidx.room:room-ktx:2.4.2"
- kapt "androidx.room:room-compiler:2.4.2"
-
- // 协程支持
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
-
- // ViewModel 和 LiveData
- implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
- implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
-
- testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
- }
复制代码 点击 “Sync Now” 同步项目。
2. 数据库设计
假设我们要创建一个简单的条记应用,包含以下数据表:
- notes 表:
- id: 主键,自增
- title: 条记标题
- content: 条记内容
- created_at: 创建时间
- updated_at: 更新时间
3. 实现数据库
3.1 创建实体类 (Entity)
在 com.yourpackage.model 包下创建 Note.kt 文件:
- import androidx.room.Entity
- import androidx.room.PrimaryKey
- import java.util.*
- @Entity(tableName = "notes")
- data class Note(
- @PrimaryKey(autoGenerate = true)
- val id: Long = 0,
-
- var title: String,
- var content: String,
-
- val created_at: Date = Date(),
- var updated_at: Date = Date()
- )
复制代码 3.2 创建数据访问对象 (DAO)
在 com.yourpackage.dao 包下创建 NoteDao.kt 文件:
- import androidx.lifecycle.LiveData
- import androidx.room.*
- import com.yourpackage.model.Note
- @Dao
- interface NoteDao {
-
- @Insert(onConflict = OnConflictStrategy.REPLACE)
- suspend fun insertNote(note: Note): Long
-
- @Update
- suspend fun updateNote(note: Note)
-
- @Delete
- suspend fun deleteNote(note: Note)
-
- @Query("SELECT * FROM notes ORDER BY updated_at DESC")
- fun getAllNotes(): LiveData<List<Note>>
-
- @Query("SELECT * FROM notes WHERE id = :noteId")
- suspend fun getNoteById(noteId: Long): Note?
-
- @Query("SELECT * FROM notes WHERE title LIKE :query OR content LIKE :query ORDER BY updated_at DESC")
- fun searchNotes(query: String): LiveData<List<Note>>
- }
复制代码 3.3 创建数据库类
在 com.yourpackage.database 包下创建 AppDatabase.kt 文件:
- import android.content.Context
- import androidx.room.Database
- import androidx.room.Room
- import androidx.room.RoomDatabase
- import com.yourpackage.dao.NoteDao
- import com.yourpackage.model.Note
- @Database(entities = [Note::class], version = 1, exportSchema = false)
- abstract class AppDatabase : RoomDatabase() {
-
- abstract fun noteDao(): NoteDao
-
- companion object {
- @Volatile
- private var INSTANCE: AppDatabase? = null
-
- fun getDatabase(context: Context): AppDatabase {
- return INSTANCE ?: synchronized(this) {
- val instance = Room.databaseBuilder(
- context.applicationContext,
- AppDatabase::class.java,
- "notes_database"
- )
- .fallbackToDestructiveMigration() // 数据库升级策略,简单应用可以这样设置
- .build()
- INSTANCE = instance
- instance
- }
- }
- }
- }
复制代码 4. 创建 Repository
在 com.yourpackage.repository 包下创建 NoteRepository.kt 文件:
- import androidx.lifecycle.LiveData
- import com.yourpackage.dao.NoteDao
- import com.yourpackage.model.Note
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.withContext
- class NoteRepository(private val noteDao: NoteDao) {
-
- val allNotes: LiveData<List<Note>> = noteDao.getAllNotes()
-
- suspend fun insert(note: Note): Long {
- return withContext(Dispatchers.IO) {
- noteDao.insertNote(note)
- }
- }
-
- suspend fun update(note: Note) {
- withContext(Dispatchers.IO) {
- note.updated_at = Date()
- noteDao.updateNote(note)
- }
- }
-
- suspend fun delete(note: Note) {
- withContext(Dispatchers.IO) {
- noteDao.deleteNote(note)
- }
- }
-
- suspend fun getNoteById(id: Long): Note? {
- return withContext(Dispatchers.IO) {
- noteDao.getNoteById(id)
- }
- }
-
- fun searchNotes(query: String): LiveData<List<Note>> {
- return noteDao.searchNotes("%$query%")
- }
- }
复制代码 5. 创建 ViewModel
在 com.yourpackage.viewmodel 包下创建 NoteViewModel.kt 文件:
- import androidx.lifecycle.ViewModel
- import androidx.lifecycle.ViewModelProvider
- import androidx.lifecycle.asLiveData
- import androidx.lifecycle.viewModelScope
- import com.yourpackage.model.Note
- import com.yourpackage.repository.NoteRepository
- import kotlinx.coroutines.launch
- class NoteViewModel(private val repository: NoteRepository) : ViewModel() {
-
- val allNotes = repository.allNotes
-
- fun insert(note: Note) = viewModelScope.launch {
- repository.insert(note)
- }
-
- fun update(note: Note) = viewModelScope.launch {
- repository.update(note)
- }
-
- fun delete(note: Note) = viewModelScope.launch {
- repository.delete(note)
- }
-
- fun getNoteById(id: Long) = viewModelScope.launch {
- repository.getNoteById(id)
- }
-
- fun searchNotes(query: String) = repository.searchNotes(query).asLiveData()
- }
- class NoteViewModelFactory(private val repository: NoteRepository) : ViewModelProvider.Factory {
- override fun <T : ViewModel> create(modelClass: Class<T>): T {
- if (modelClass.isAssignableFrom(NoteViewModel::class.java)) {
- @Suppress("UNCHECKED_CAST")
- return NoteViewModel(repository) as T
- }
- throw IllegalArgumentException("Unknown ViewModel class")
- }
- }
复制代码 6. 实现 UI 层
6.1 创建条记列表 Activity
创建 NotesListActivity.kt 和对应的结构文件 activity_notes_list.xml
activity_notes_list.xml
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.coordinatorlayout.widget.CoordinatorLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".ui.NotesListActivity">
- <com.google.android.material.appbar.AppBarLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:theme="@style/Theme.SQLiteDemo.AppBarOverlay">
- <androidx.appcompat.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- app:popupTheme="@style/Theme.SQLiteDemo.PopupOverlay"
- app:title="@string/app_name" />
- <com.google.android.material.textfield.TextInputLayout
- android:id="@+id/search_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
- <com.google.android.material.textfield.TextInputEditText
- android:id="@+id/search_input"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/search_hint"
- android:imeOptions="actionSearch"
- android:inputType="text" />
- </com.google.android.material.textfield.TextInputLayout>
- </com.google.android.material.appbar.AppBarLayout>
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/notes_recycler_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipToPadding="false"
- android:paddingBottom="72dp"
- app:layout_behavior="@string/appbar_scrolling_view_behavior" />
- <com.google.android.material.floatingactionbutton.FloatingActionButton
- android:id="@+id/fab_add_note"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|end"
- android:layout_margin="16dp"
- android:contentDescription="@string/add_note"
- android:src="@drawable/ic_add"
- app:backgroundTint="@color/purple_500"
- app:tint="@android:color/white" />
- </androidx.coordinatorlayout.widget.CoordinatorLayout>
复制代码 NotesListActivity.kt
6.2 创建条记详情 Activity
创建 NoteDetailActivity.kt 和对应的结构文件 activity_note_detail.xml
activity_note_detail.xml
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.coordinatorlayout.widget.CoordinatorLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".ui.NoteDetailActivity">
- <com.google.android.material.appbar.AppBarLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:theme="@style/Theme.SQLiteDemo.AppBarOverlay">
- <androidx.appcompat.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- app:popupTheme="@style/Theme.SQLiteDemo.PopupOverlay" />
- </com.google.android.material.appbar.AppBarLayout>
- <androidx.core.widget.NestedScrollView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:layout_behavior="@string/appbar_scrolling_view_behavior">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:padding="16dp">
- <com.google.android.material.textfield.TextInputLayout
- android:id="@+id/title_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
- <com.google.android.material.textfield.TextInputEditText
- android:id="@+id/title_input"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/title_hint"
- android:inputType="textCapSentences|textAutoCorrect"
- android:maxLines="1" />
- </com.google.android.material.textfield.TextInputLayout>
- <com.google.android.material.textfield.TextInputLayout
- android:id="@+id/content_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
- <com.google.android.material.textfield.TextInputEditText
- android:id="@+id/content_input"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="@string/content_hint"
- android:inputType="textMultiLine|textCapSentences|textAutoCorrect"
- android:minLines="5"
- android:gravity="top" />
- </com.google.android.material.textfield.TextInputLayout>
- </LinearLayout>
- </androidx.core.widget.NestedScrollView>
- <com.google.android.material.floatingactionbutton.FloatingActionButton
- android:id="@+id/fab_save"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|end"
- android:layout_margin="16dp"
- android:contentDescription="@string/save_note"
- android:src="@drawable/ic_save"
- app:backgroundTint="@color/purple_500"
- app:tint="@android:color/white" />
- </androidx.coordinatorlayout.widget.CoordinatorLayout>
复制代码 NoteDetailActivity.kt
- import android.os.Bundle
- import android.text.Editable
- import android.text.TextWatcher
- import android.view.MenuItem
- import androidx.activity.viewModels
- import androidx.appcompat.app.AppCompatActivity
- import com.google.android.material.snackbar.Snackbar
- import com.yourpackage.R
- import com.yourpackage.databinding.ActivityNoteDetailBinding
- import com.yourpackage.model.Note
- import com.yourpackage.viewmodel.NoteViewModel
- import com.yourpackage.viewmodel.NoteViewModelFactory
- import java.util.*
- class NoteDetailActivity : AppCompatActivity() {
-
- companion object {
- const val EXTRA_NOTE_ID = "extra_note_id"
- }
-
- private lateinit var binding: ActivityNoteDetailBinding
- private val viewModel: NoteViewModel by viewModels {
- NoteViewModelFactory((application as NotesApplication).repository)
- }
-
- private var noteId: Long = -1L
- private var isNewNote = true
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- binding = ActivityNoteDetailBinding.inflate(layoutInflater)
- setContentView(binding.root)
-
- setSupportActionBar(binding.toolbar)
- supportActionBar?.setDisplayHomeAsUpEnabled(true)
-
- noteId = intent.getLongExtra(EXTRA_NOTE_ID, -1L)
- isNewNote = noteId == -1L
-
- if (!isNewNote) {
- loadNote()
- }
-
- setupSaveButton()
- setupTextWatchers()
- }
-
- private fun loadNote() {
- viewModel.getNoteById(noteId)
- viewModel.allNotes.observe(this) { notes ->
- notes.find { it.id == noteId }?.let { note ->
- binding.titleInput.setText(note.title)
- binding.contentInput.setText(note.content)
- }
- }
- }
-
- private fun setupSaveButton() {
- binding.fabSave.setOnClickListener {
- saveNote()
- }
- }
-
- private fun setupTextWatchers() {
- binding.titleInput.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
- override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
- override fun afterTextChanged(s: Editable?) {
- validateInputs()
- }
- })
-
- binding.contentInput.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
- override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
- override fun afterTextChanged(s: Editable?) {
- validateInputs()
- }
- })
- }
-
- private fun validateInputs(): Boolean {
- val titleValid = binding.titleInput.text?.isNotBlank() ?: false
- val contentValid = binding.contentInput.text?.isNotBlank() ?: false
-
- binding.titleLayout.error = if (!titleValid) getString(R.string.title_required) else null
- binding.contentLayout.error = if (!contentValid) getString(R.string.content_required) else null
-
- return titleValid && contentValid
- }
-
- private fun saveNote() {
- if (!validateInputs()) return
-
- val title = binding.titleInput.text.toString()
- val content = binding.contentInput.text.toString()
-
- if (isNewNote) {
- val note = Note(title = title, content = content)
- viewModel.insert(note)
- Snackbar.make(binding.root, "Note saved", Snackbar.LENGTH_SHORT).show()
- finish()
- } else {
- viewModel.allNotes.value?.find { it.id == noteId }?.let { existingNote ->
- val updatedNote = existingNote.copy(
- title = title,
- content = content,
- updated_at = Date()
- )
- viewModel.update(updatedNote)
- Snackbar.make(binding.root, "Note updated", Snackbar.LENGTH_SHORT).show()
- finish()
- }
- }
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return when (item.itemId) {
- android.R.id.home -> {
- onBackPressed()
- true
- }
- else -> super.onOptionsItemSelected(item)
- }
- }
- }
复制代码 6.3 创建 RecyclerView Adapter
在 com.yourpackage.adapter 包下创建 NotesAdapter.kt 文件:
- import android.view.LayoutInflater
- import android.view.View
- import android.view.ViewGroup
- import androidx.recyclerview.widget.DiffUtil
- import androidx.recyclerview.widget.ListAdapter
- import androidx.recyclerview.widget.RecyclerView
- import com.yourpackage.R
- import com.yourpackage.databinding.ItemNoteBinding
- import com.yourpackage.model.Note
- import java.text.SimpleDateFormat
- import java.util.*
- class NotesAdapter(private val onItemClick: (Note) -> Unit) :
- ListAdapter<Note, NotesAdapter.NoteViewHolder>(NoteDiffCallback()) {
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
- val binding = ItemNoteBinding.inflate(
- LayoutInflater.from(parent.context),
- parent,
- false
- )
- return NoteViewHolder(binding, onItemClick)
- }
-
- override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
- holder.bind(getItem(position))
- }
-
- class NoteViewHolder(
- private val binding: ItemNoteBinding,
- private val onItemClick: (Note) -> Unit
- ) : RecyclerView.ViewHolder(binding.root) {
-
- fun bind(note: Note) {
- binding.apply {
- noteTitle.text = note.title
- noteContent.text = note.content
-
- val dateFormat = SimpleDateFormat("MMM dd, yyyy - hh:mm a", Locale.getDefault())
- noteDate.text = dateFormat.format(note.updated_at)
-
- root.setOnClickListener {
- onItemClick(note)
- }
- }
- }
- }
-
- private class NoteDiffCallback : DiffUtil.ItemCallback<Note>() {
- override fun areItemsTheSame(oldItem: Note, newItem: Note): Boolean {
- return oldItem.id == newItem.id
- }
-
- override fun areContentsTheSame(oldItem: Note, newItem: Note): Boolean {
- return oldItem == newItem
- }
- }
- }
复制代码 创建对应的列表项结构文件 item_note.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <com.google.android.material.card.MaterialCardView
- 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="wrap_content"
- android:layout_margin="8dp"
- app:cardCornerRadius="8dp"
- app:cardElevation="4dp">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:padding="16dp">
- <TextView
- android:id="@+id/note_title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.AppCompat.Headline"
- android:textColor="@android:color/black" />
- <TextView
- android:id="@+id/note_content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:ellipsize="end"
- android:maxLines="2"
- android:textAppearance="@style/TextAppearance.AppCompat.Body1"
- android:textColor="@android:color/darker_gray" />
- <TextView
- android:id="@+id/note_date"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:textAppearance="@style/TextAppearance.AppCompat.Caption"
- android:textColor="@android:color/darker_gray" />
- </LinearLayout>
- </com.google.android.material.card.MaterialCardView>
复制代码 6.4 创建 Application 类
在 com.yourpackage 包下创建 NotesApplication.kt 文件:
- import android.app.Application
- import com.yourpackage.database.AppDatabase
- import com.yourpackage.repository.NoteRepository
- class NotesApplication : Application() {
-
- val database by lazy { AppDatabase.getDatabase(this) }
- val repository by lazy { NoteRepository(database.noteDao()) }
- }
复制代码 更新 AndroidManifest.xml 文件,添加 android:name 属性:
- <application
- android:name=".NotesApplication"
- android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
- android:supportsRtl="true"
- android:theme="@style/Theme.SQLiteDemo">
- <!-- 其他配置 -->
- </application>
复制代码 7. 添加菜单资源
在 res/menu 目录下创建 menu_main.xml 文件:
- <?xml version="1.0" encoding="utf-8"?>
- <menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
-
- <item
- android:id="@+id/action_delete_all"
- android:icon="@drawable/ic_delete"
- android:title="@string/delete_all"
- app:showAsAction="never" />
- </menu>
复制代码 8. 添加字符串资源
在 res/values/strings.xml 文件中添加以下字符串:
- <resources>
- <string name="app_name">SQLite Notes</string>
- <string name="title_hint">Title</string>
- <string name="content_hint">Content</string>
- <string name="search_hint">Search notes...</string>
- <string name="add_note">Add new note</string>
- <string name="save_note">Save note</string>
- <string name="delete_all">Delete all notes</string>
- <string name="title_required">Title is required</string>
- <string name="content_required">Content is required</string>
- </resources>
复制代码 9. 添加图标资源
确保在 res/drawable 目录下有以下矢量图标:
- ic_add.xml (添加按钮图标)
- ic_save.xml (生存按钮图标)
- ic_delete.xml (删除按钮图标)
10. 运行和测试应用
现在,您可以运行应用程序并测试以下功能:
- 添加新条记
- 查看条记列表
- 编辑现有条记
- 删除条记
- 搜刮条记
- 删除所有条记
11. 数据库调试本事
11.1 查看数据库内容
- 在 Android Studio 中打开 “Device File Explorer” (View -> Tool Windows -> Device File Explorer)
- 导航到 /data/data/com.yourpackage/databases/
- 找到 notes_database 文件
- 右键点击并选择 “Save As” 将其生存到本地
- 使用 SQLite 浏览器工具(如 DB Browser for SQLite)打开该文件查看内容
11.2 使用 Stetho 进行调试
添加 Stetho 依赖到 build.gradle:
- implementation 'com.facebook.stetho:stetho:1.6.0'
复制代码 在 NotesApplication.kt 中初始化 Stetho:
- import com.facebook.stetho.Stetho
- class NotesApplication : Application() {
- override fun onCreate() {
- super.onCreate()
- Stetho.initializeWithDefaults(this)
- }
-
- // 其他代码...
- }
复制代码 运行应用后,在 Chrome 浏览器中访问 chrome://inspect 可以查看和调试数据库。
12. 数据库迁移
当您需要更改数据库结构时(比方添加新表或修改现有表),需要进行数据库迁移。
12.1 修改实体类
比方,我们要为 Note 添加一个 is_pinned 字段:
- @Entity(tableName = "notes")
- data class Note(
- // 现有字段...
- var is_pinned: Boolean = false
- )
复制代码 12.2 更新数据库版本
修改 AppDatabase.kt:
- @Database(entities = [Note::class], version = 2, exportSchema = false)
- abstract class AppDatabase : RoomDatabase() {
- // ...
- }
复制代码 12.3 添加迁移策略
- val migration1to2 = object : Migration(1, 2) {
- override fun migrate(database: SupportSQLiteDatabase) {
- database.execSQL("ALTER TABLE notes ADD COLUMN is_pinned INTEGER NOT NULL DEFAULT 0")
- }
- }
- // 在 databaseBuilder 中添加迁移
- val instance = Room.databaseBuilder(
- context.applicationContext,
- AppDatabase::class.java,
- "notes_database"
- )
- .addMigrations(migration1to2)
- .build()
复制代码 13. 性能优化建议
- 使用事件:对于批量操作,使用事件可以显著进步性能:
- @Dao
- interface NoteDao {
- @Transaction
- suspend fun insertAll(notes: List<Note>) {
- notes.forEach { insertNote(it) }
- }
- }
复制代码- @Entity(tableName = "notes", indices = [Index(value = ["title"], unique = false)])
- data class Note(
- // ...
- )
复制代码- @Query("SELECT * FROM notes ORDER BY updated_at DESC")
- fun getPagedNotes(): PagingSource<Int, Note>
复制代码
- 避免在主线程操作数据库:始终确保数据库操作在后台线程执行。
14. 完整项目结构
终极项目结构应类似于:
- com.yourpackage
- ├── adapter
- │ └── NotesAdapter.kt
- ├── dao
- │ └── NoteDao.kt
- ├── database
- │ └── AppDatabase.kt
- ├── model
- │ └── Note.kt
- ├── repository
- │ └── NoteRepository.kt
- ├── ui
- │ ├── NotesListActivity.kt
- │ └── NoteDetailActivity.kt
- ├── viewmodel
- │ ├── NoteViewModel.kt
- │ └── NoteViewModelFactory.kt
- └── NotesApplication.kt
复制代码 15. 总结
本指南具体介绍了在 Android Studio 中使用 SQLite 数据库的完整开发流程,包罗:
- 设置项目和依赖
- 设计数据库结构
- 实现 Room 数据库组件(Entity, DAO, Database)
- 创建 Repository 层
- 实现 ViewModel
- 构建用户界面
- 添加数据库迁移支持
- 性能优化建议
通过遵照这些步调,您可以构建一个功能美满、结构清晰的 Android 应用,充实利用 SQLite 数据库的强大功能。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |