使用 LiveData 和 JetPack Compose 从 RoomDb 插入和读取数据 Android Kotlin
13
0
该项目使用 Jetpack Compose、Room Database 和 LiveData 实现了一个基本的笔记应用程序。以下是主要组件和代码流程的概述:主要组件:数据库和数据
该项目使用 Jetpack Compose、Room Database 和 LiveData 实现了一个基本的笔记应用程序。以下是关键组件和代码流程的概述:
主要组件:数据库和数据模型:
Notes: A data entity representing a note with an ID, title, and description.
NotesDao: Data Access Object (DAO) containing functions for database operations (insert, delete, fetch).
NotesDatabase: Singleton class for Room database configuration, providing access to the DAO.
Repository:
NotesRepository: Abstracts data operations, connecting the ViewModel to the Room database. Provides methods to fetch, add, and delete notes.
ViewModel:
NoteViewModel: Manages UI-related data by exposing LiveData for observing notes and handles adding/removing notes in a background thread using Kotlin coroutines.
NoteViewModelFactory: Provides the ViewModel with a repository instance.
UI Components (Jetpack Compose):
MainActivity: Initializes the database, repository, ViewModel, and renders the NoteScreen composable.
NoteScreen: Displays the list of notes and allows adding/removing notes via input fields and a save button. Uses LiveData to observe and update the UI when the data changes.
NoteRow: Renders individual notes in a list.
NoteInput: Input field for note title and description.
NoteButton: Button for saving notes.
Code Flow:
MainActivity initializes the Room database, repository, and ViewModel.
NoteScreen observes the LiveData from the ViewModel and renders the list of notes using a LazyColumn.
The user can add a new note via input fields and the save button, triggering the addNote() function in the ViewModel.
The removeNote() function handles note deletion.
The ViewModel interacts with the repository, which in turn communicates with Room to perform database operations.
The app is designed using modern Android architecture principles, leveraging Jetpack Compose for UI, Room for data persistence, and LiveData/ViewModel for lifecycle-aware data handling.
使用 LiveData 和 JetPack Compose 从 RoomDb 插入和读取数据 Android Kotlin
下载声明: 本站所有软件和资料均为软件作者提供或网友推荐发布而来,仅供学习和研究使用,不得用于任何商业用途。如本站不慎侵犯你的版权请联系我,我将及时处理,并撤下相关内容!
下载声明: 本站所有软件和资料均为软件作者提供或网友推荐发布而来,仅供学习和研究使用,不得用于任何商业用途。如本站不慎侵犯你的版权请联系我,我将及时处理,并撤下相关内容!
收藏的用户(0)
X
正在加载信息~
-
引用 2楼
Add below libraries module app gradle file plugins { alias(libs.plugins.kotlin.kapt) } // Room DB implementation (libs.androidx.room.ktx) implementation (libs.androidx.room.runtime) annotationProcessor (libs.androidx.room.compiler) kapt (libs.androidx.room.compiler) //LiveData implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.runtime.livedata) [libraries] androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomKtx" } androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "roomKtx" } androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomKtx" } androidx-runtime-livedata = { module = "androidx.compose.runtime:runtime-livedata", version.ref = "runtimeLivedata" } androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" } [versions] kaptVersion = "1.9.0" runtimeLivedata = "1.7.0" roomKtx = "2.6.1" lifecycleRuntimeKtx = "2.8.4" agp = "8.4.0-rc02" kotlin = "1.9.0" [plugins] android-application = { id = "com.android.application", version.ref = "agp" } jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kaptVersion"} //build gradle file(Project level) plugins{ alias(libs.plugins.kotlin.kapt) apply false } //MainActivity class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { NoteAppTheme { Surface(modifier = Modifier.fillMaxSize()) { val userDao = NotesDatabase.getDatabase(this).notesDao() val repository = NotesRepository(userDao) val factory = NoteViewModelFactory(repository) val noteViewModel = ViewModelProvider(this,factory)[NoteViewModel::class.java] NoteScreen(noteViewModel) } } } } } @Composable fun NoteScreen(noteViewModel: NoteViewModel? = viewModel()) { val noteListState = noteViewModel?.readAllData?.observeAsState(initial = emptyList()) val noteList = noteListState?.value ?: emptyList() NoteScreen(notes = noteList, onAddNote = { noteViewModel?.addNote(it) }, onRemoveNote = { noteViewModel?.removeNote(it) }) } // NoteScreen @OptIn(ExperimentalMaterial3Api::class) @Composable fun NoteScreen(notes: List<Notes>, onAddNote: (Notes) -> Unit, onRemoveNote: (Notes) -> Unit) { var title by remember { mutableStateOf("") } var description by remember { mutableStateOf("") } Column { TopAppBar(title = { Text(text = stringResource(id = R.string.app_name)) }, actions = { Icon(imageVector = Icons.Rounded.Notifications, contentDescription = "Notification icon") }, colors = TopAppBarDefaults.topAppBarColors( containerColor = Color.LightGray )) val context = LocalContext.current Column(modifier = Modifier.padding(16.dp)) { NoteInput(modifier = Modifier.fillMaxWidth(), label = "Title", text = title, onTextChange = { if(it.all { char -> char.isLetter() || char.isWhitespace() }) title = it }) Spacer(modifier = Modifier.height(10.dp)) NoteInput(modifier = Modifier.fillMaxWidth(), label = "Add a note", text = description, onTextChange = { if (it.all { char -> char.isLetter() || char.isWhitespace() }) description = it }) Spacer(modifier = Modifier.height(10.dp)) NoteButton(text = "Save", enabled = title.isNotEmpty() && description.isNotEmpty(), onClick = { if (title.isNotEmpty() && description.isNotEmpty()) { onAddNote(Notes(title = title, description = description)) Toast.makeText(context, "Added note $title", Toast.LENGTH_SHORT).show() title = "" description = "" } }, modifier = Modifier.align( alignment = Alignment.CenterHorizontally )) Divider(modifier = Modifier.padding(10.dp)) LazyColumn { items(notes) { note -> NoteRow(onClick = { onRemoveNote(note) }, note = note) } } } } } @Composable fun NoteRow( modifier: Modifier = Modifier, onClick: (Notes) -> Unit, note: Notes, ){ Surface(modifier = modifier .padding(10.dp) .clip(RoundedCornerShape(topEnd = 33.dp, bottomStart = 33.dp)) .fillMaxWidth(), color = Color.Cyan, tonalElevation = 4.dp){ Column(modifier = modifier .clickable { onClick(note) } .padding(horizontal = 12.dp, vertical = 8.dp), horizontalAlignment = Alignment.Start) { Text(text = note.title, style = MaterialTheme.typography.titleSmall) Text(text = note.description, style = MaterialTheme.typography.bodySmall) } } } //Note Input class @OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) @Composable fun NoteInput( modifier: Modifier, label: String, text: String, maxLine: Int = 1, onTextChange: (String) -> Unit, onImeAction: () -> Unit = {} ) { val keyboardController = LocalSoftwareKeyboardController.current TextField(value = text, onValueChange = onTextChange, colors = TextFieldDefaults.textFieldColors( containerColor = Color.Transparent ), label = { Text(text = label) }, maxLines = maxLine, keyboardOptions = KeyboardOptions.Default.copy( imeAction = ImeAction.Done ), keyboardActions = KeyboardActions(onDone = { onImeAction() keyboardController?.hide() }), modifier = modifier ) } @Composable fun NoteButton( modifier: Modifier = Modifier, text: String, onClick: () -> Unit, enabled: Boolean = false, ) { Button(onClick = { onClick.invoke() }, shape = CircleShape, enabled = enabled, modifier = modifier, ) { Text(text = text) } } //Repository class NotesRepository(private val notesDao: NotesDao) { fun fetchNotes(): LiveData<List<Notes>> = notesDao.fetchNotesData() suspend fun addNotes(notes: Notes) = notesDao.insertData(notes) } //Data entity model @Entity(tableName = "notes_table") data class Notes( @PrimaryKey(autoGenerate = true) val id: Int = 0, val title: String, val description: String ) //Dao Class @Dao interface NotesDao { @Insert(onConflict = OnConflictStrategy.IGNORE) suspend fun insertData(note: Notes) @Query("SELECT * FROM notes_table ORDER BY id ASC") fun fetchNotesData(): LiveData<List<Notes>> @Delete suspend fun deleteNote(notes: Notes) } //Database @Database(entities = [Notes::class], version = 1, exportSchema = false) abstract class NotesDatabase : RoomDatabase() { abstract fun notesDao(): NotesDao companion object { var DATABASE_INSTANCE: NotesDatabase? = null fun getDatabase(context: Context): NotesDatabase { val tempInstance = DATABASE_INSTANCE if (tempInstance != null) { return tempInstance } synchronized(this) { val instance = Room.databaseBuilder( context.applicationContext, NotesDatabase::class.java, "notes_database" ).build() DATABASE_INSTANCE = instance return instance } } } } //Repository class NotesRepository(private val notesDao: NotesDao) { fun fetchNotes(): LiveData<List<Notes>> = notesDao.fetchNotesData() suspend fun addNotes(notes: Notes) = notesDao.insertData(notes) suspend fun deleteNote(notes: Notes) = notesDao.deleteNote(notes) } //ViewModel import androidx.compose.runtime.mutableStateListOf import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.noteapp.model.Notes import com.example.noteapp.repository.NotesRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class NoteViewModel(private val repository: NotesRepository) : ViewModel() { var readAllData: LiveData<List<Notes>> init { readAllData = repository.fetchNotes() } fun addNote(note: Notes) { viewModelScope.launch(Dispatchers.IO) { repository.addNotes(note) } } fun removeNote(note: Notes) { noteList.remove(note) } fun getAllNotes(): LiveData<List<Notes>> { return readAllData } } class NoteViewModelFactory(private val repository: NotesRepository) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>): T { if (modelClass.isAssignableFrom(NoteViewModel::class.java)) { return NoteViewModel(repository) as T } throw IllegalArgumentException("Unknown ViewModel class") } }