8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

使用 LiveData 和 JetPack Compose 从 RoomDb 插入和读取数据 Android Kotlin

EFERYEG 1月前

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.
帖子版权声明 1、本帖标题:使用 LiveData 和 JetPack Compose 从 RoomDb 插入和读取数据 Android Kotlin
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由EFERYEG在本站《kotlin》版块原创发布, 转载请注明出处!
最新回复 (0)
  •     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")
        }
    }
    
返回
作者最近主题: