【筆記】使用 ViewModel, Room 的 jetpack compose 小範例 (By ChatGPT)

最近 ChatGPT 很紅,我剛剛請它寫給我一個使用 ViewModel, Room 的 jetpack compose 小範例,它實在是太強了。以下筆記一下它寫的內容。


Todo App with Jetpack.

以下是一個使用 ViewModel、Room 和 Jetpack Compose 構建簡單 Todo App 的範例:

//build.gradle(Module:app)

plugins {
    //...
    id 'kotlin-kapt'
}

dependencies { 
    //...

    //room
    implementation "androidx.room:room-runtime:2.5.0"
    implementation "androidx.room:room-ktx:2.5.0"
    annotationProcessor "androidx.room:room-compiler:2.5.0"
    kapt "androidx.room:room-compiler:2.5.0"


    //livedata
    implementation "androidx.compose.runtime:runtime-livedata:1.3.3"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
}

首先,定義一個數據模型:

@Entity(tableName = "todos")
data class Todo(
    @PrimaryKey(autoGenerate = true) 
    val id: Int = 0,
    // 或是把上兩行改成如下
    // @PrimaryKey
    // val id: String = UUID.randomUUID().toString(),
    val title: String,
    val description: String
)

為了操作 Todo 對象,我們需要創建一個 Dao:

@Dao
interface TodoDao {
    @Query("SELECT * FROM todos")
    fun getTodos(): Flow<List<Todo>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun addOrUpdate(todo: Todo)

    @Delete
    suspend fun delete(todo: Todo)
}

接下來,我們創建一個 Room 數據庫:

@Database(entities = [Todo::class], version = 1)
abstract class TodoDatabase : RoomDatabase() {
    abstract fun todoDao(): TodoDao

    companion object {
        @Volatile
        private var INSTANCE: TodoDatabase? = null

        fun getDatabase(context: Context): TodoDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    TodoDatabase::class.java,
                    "todo_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

現在,我們創建一個 ViewModel 來管理數據庫操作:

class TodoViewModel(application: Application) : AndroidViewModel(application) {
    private val todoDao = TodoDatabase.getDatabase(application).todoDao()

    val todos: LiveData<List<Todo>> = todoDao.getTodos().asLiveData()

    fun addOrUpdate(todo: Todo) {
        viewModelScope.launch {
            todoDao.addOrUpdate(todo)
        }
    }

    fun delete(todo: Todo) {
        viewModelScope.launch {
            todoDao.delete(todo)
        }
    }
}

最後,我們使用 Jetpack Compose 創建 UI:

@Composable
fun TodoListScreen(todoViewModel: TodoViewModel) {
    val todos by todoViewModel.todos.observeAsState(emptyList())

    Column {
        TodoList(todos = todos)
        TodoInput(onAddTodo = { title, description ->
            todoViewModel.addOrUpdate(Todo(title = title, description = description))
        })
    }
}

@Composable
fun TodoList(todos: List<Todo>) {
    LazyColumn {
        items(todos) { todo ->
            TodoItem(todo)
        }
    }
}

@Composable
fun TodoItem(todo: Todo) {
    Card(
        modifier = Modifier
            .padding(16.dp)
            .fillMaxWidth()
    ) {
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            Text(text = todo.title, style = MaterialTheme.typography.h6)
            Text(text = todo.description, style = MaterialTheme.typography.body1)
        }
    }
}

@Composable
fun TodoInput(onAddTodo: (title: String, description: String) -> Unit) {
    var title by rememberSaveable { mutableStateOf("") }
    var description by rememberSaveable { mutableStateOf("") }

    Column {
        OutlinedTextField(
            value = title,
            onValueChange = { title = it },
            label = { Text(text = "Title") },
            modifier = Modifier
                .padding(16)
                .fillMaxWidth()
        )

        OutlinedTextField(
            value = description,
            onValueChange = { description = it },
            label = { Text(text = "Description") },
            modifier = Modifier
                .padding(16.dp)
                .fillMaxWidth()
        )

        Button(
            onClick = { onAddTodo.invoke(title, description) },
            modifier = Modifier
                .padding(16.dp)
                .align(Alignment.End)
        ) {
            Text(text = "Add")
        }
}

最後,將 TodoListScreen 加入到 MainActivity:


class MainActivity : ComponentActivity() {
    private val todoViewModel: TodoViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TodoListScreen(todoViewModel)
        }
    }
}

這樣就完成了一個使用 ViewModel、Room 和 Jetpack Compose 構建的簡單 Todo App,當用戶添加或刪除代辦事項時,它將自動更新。


留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *