In this Jetpack Compose tutorial we are createing a simple ToDo application using Room Database and ViewModel LiveData components.
In this Compose Todo application we will create Notes, edit notes, update notes and delete notes.
What we will cover
Let's get started
Step 1: Create Compose Application in Android studio
Step 2: Add required dependencies in build.gradle file
plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-kapt' } android { compileSdk 30 defaultConfig { applicationId "com.rrtutors.todoapplication" minSdk 21 targetSdk 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary true } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' useIR = true } buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion compose_version kotlinCompilerVersion '1.5.10' } packagingOptions { resources { excludes += '/META-INF/{AL2.0,LGPL2.1}' } } } dependencies { implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.material:material:1.4.0' implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.material:material:$compose_version" implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' implementation 'androidx.activity:activity-compose:1.3.1' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" def room_version = "2.3.0" implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-ktx:$room_version" kapt "androidx.room:room-compiler:$room_version" implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha07' implementation 'androidx.compose.runtime:runtime-livedata:1.0.4' } |
Step 3: Create Room Database
Singleton Room instance
We are creating the singleton room database with below code
package com.rrtutors.todoapplication import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase import android.content.Context @Database(entities = [ToDo::class], version = 1, exportSchema = false) abstract class RoomSingleton : RoomDatabase() { abstract fun todoDao():TodoDAO companion object { private var INSTANCE: RoomSingleton? = null fun getInstance(context: Context): RoomSingleton { if (INSTANCE == null) { INSTANCE = Room.databaseBuilder( context, RoomSingleton::class.java, "roomdb") .build() } return INSTANCE as RoomSingleton } } } |
Here we need to create Todo Dao and Todo Entities respectively.
Todo Entity
package com.rrtutors.todoapplication import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey @Entity(tableName = "todoTBL") class ToDo( @PrimaryKey var id:Long?, @ColumnInfo(name = "uuid") var fullName: String, @ColumnInfo(name = "notes") var notes:String) { } |
Todo Dao
package com.rrtutors.todoapplication import androidx.lifecycle.LiveData import androidx.room.* @Dao interface TodoDAO { @Query("SELECT * FROM todoTBL ORDER BY id DESC") fun getTodos(): LiveData<MutableList<ToDo>> @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insert(todo:ToDo) @Update suspend fun update(todo:ToDo) @Delete suspend fun delete(todo:ToDo) @Query("DELETE FROM todoTBL") suspend fun clear() } |
Create ViewModel and ViewModelFactory
Now let's create ViewModel and ViewModelFactory which will handle the Notes data from/to Room Database
package com.rrtutors.todoapplication import android.app.Application import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.room.RoomDatabase import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class TodoViewModel(application:Application):ViewModel() { private val db=RoomSingleton.getInstance(application) internal val todoList:LiveData<MutableList<ToDo>> = db.todoDao().getTodos() fun insert(todo: ToDo){ viewModelScope.launch(Dispatchers.IO) { db.todoDao().insert(todo) } } fun update(todo: ToDo){ viewModelScope.launch(Dispatchers.IO) { db.todoDao().update(todo) } } fun delete(todo: ToDo){ viewModelScope.launch(Dispatchers.IO) { db.todoDao().delete(todo) } } fun clear(){ viewModelScope.launch(Dispatchers.IO) { db.todoDao().clear() } } } |
ViewModelFactory
package com.rrtutors.todoapplication
import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
class ToDoViewmodelFactory(private val application: Application):ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(TodoViewModel::class.java)) {
return TodoViewModel(application) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
|
Now we need to design our UI to add Notes and Display data on list
package com.rrtutors.todoapplication import android.app.Application import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Refresh import androidx.compose.runtime.Composable import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import kotlinx.coroutines.launch import java.util.* import kotlin.random.Random import com.rrtutors.todoapplication.ui.theme.ToDoApplicationTheme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ToDoApplicationTheme { // A surface container using the 'background' color from the theme Surface(color = MaterialTheme.colors.background) { GetScaffold() } } } } } @Composable fun GetScaffold(){ val scaffoldState: ScaffoldState = rememberScaffoldState( snackbarHostState = SnackbarHostState() ) Scaffold( scaffoldState = scaffoldState, topBar = { TopAppBar( title = { Text(text = "Compose - ToDo Application",color= Color.White)}, backgroundColor = Color(0xFFFDA433), ) }, content = {MainContent(scaffoldState)}, backgroundColor = Color(0xFFBEEFF5), ) } @Composable fun MainContent(scaffoldState: ScaffoldState){ val scope = rememberCoroutineScope() val context = LocalContext.current val model : TodoViewModel = viewModel( factory = ToDoViewmodelFactory( context.applicationContext as Application ) ) val list:List<ToDo> = model.todoList.observeAsState(listOf()).value var textState = remember { mutableStateOf("") } Box( modifier = Modifier .fillMaxSize() .padding(12.dp), //contentAlignment = Alignment.Center ){ Column( verticalArrangement = Arrangement.spacedBy(12.dp) ) { TextField( modifier = Modifier .fillMaxWidth() .padding(vertical = 4.dp), shape = RoundedCornerShape(8.dp,), colors = TextFieldDefaults.textFieldColors( backgroundColor = Color(0xFFFFFFFF), focusedIndicatorColor = Color.Transparent, //hide the indicator ), value =textState.value, onValueChange ={textState.value = it} ,placeholder = { Text(text = "Enter Your Notes") },) Row( horizontalArrangement = Arrangement.spacedBy(12.dp) ){ Button( onClick = { model.insert( ToDo( null, UUID.randomUUID().toString(), textState.value ) ) scope.launch{ textState.value= "" scaffoldState.snackbarHostState.showSnackbar( message = "Notes added", ) } }) { Text(text = "Add Notes") } Button(onClick = { model.clear() scope.launch{ scaffoldState.snackbarHostState.showSnackbar( message = "All Notes deleted", ) } }) { Text(text = "Clear") } } LazyColumn( verticalArrangement = Arrangement.spacedBy(2.dp) ) { items(list.size) { index -> Card( modifier = Modifier .padding(2.dp) .fillMaxWidth() .wrapContentHeight(Alignment.CenterVertically) ) { Row( modifier = Modifier.padding(4.dp), verticalAlignment = Alignment.CenterVertically ) { Text( text = "${list[index].id}", fontWeight = FontWeight.Bold, modifier = Modifier.padding(start = 12.dp) ) Text( text = " : " + list[index].fullName.take(10), ) Text( text = " : " + list[index].notes, style = TextStyle( color = if (list[index].id!! >= 33) Color(0xFF3B7A57) else Color(0xFFAB274F)), modifier = Modifier.weight(2F) ) IconButton(onClick = { list[index].notes = textState.value model.update(list[index]) scope.launch{ scaffoldState.snackbarHostState .showSnackbar( "Notes updated id" + " : ${list[index].id}", ) textState.value= "" } }) { Icon(Icons.Filled.Edit,"",tint = Color.Magenta) } IconButton(onClick = { model.delete(list[index]) scope.launch{ scaffoldState.snackbarHostState .showSnackbar( "Notes deleted id" + " : ${list[index].id}", ) textState.value= "" } }) { Icon(Icons.Filled.Delete,"",tint = Color.Red) } } } } } } } } |
Step 5: Run Application
Conclusion: In this Jetpack Compose Tutorial we covered Create ToDo Notes application with Room Database and ViewModel, LiveData components.
Article Contributed By :
|
|
|
|
2246 Views |