0
Help us understand the problem. What are the problem?

posted at

NCMB Kotlin SDKを使ってTodoアプリを作る(その2 タスクデータの保存)

NCMBでは公式SDKとしてSwift/Objective-C/Kotlin/Java/Unity/JavaScript SDKを用意しています。また、それ以外にもコミュニティSDKとして、非公式ながらFlutter/React Native/Google Apps Script/C#/Ruby/Python/PHPなど幅広い言語向けにSDKが開発されています。

今回は公式SDKの一つ、Kotlin SDKを使ってTodoアプリを作ってみます。前回は画面の仕様とSDKの初期化について解説しましたので、今回はタスクデータの保存について解説します。

完成版のコード

作成したデモアプリのコードはNCMBMania/Kotlin_Todo: Kotlin SDKを使ったTodoアプリですにアップロードしてあります。

ナビゲーションの振り分け

今回は以下のようなナビゲーションになっています。文字列からNCMBObjectを復元するstrToNCMBObjectについては、KotlinのNavigation コンポーネントを使ってNCMBObjectを別画面に渡す - Qiitaを参照してください。

@Composable
fun Navigation() {
    val startDestination = "list"
    val navController = rememberNavController()
    val className = "Task"
    NavHost(navController = navController, startDestination = startDestination) {
        composable(route = "form") {
            val obj = NCMBObject(className)
            FormScreen(navController, obj)
        }
        composable(route = "list") {
            ListScreen(navController = navController)
        }
        composable(
            route = "detail/task={task}",
            arguments = listOf(navArgument("task") { type = NavType.StringType})
        ) { backStackEntry ->
            val obj = strToNCMBObject(backStackEntry.arguments!!.getString("task")!!, className)
            DetailScreen(navController, obj)
        }
        composable(
            route = "edit/task={task}",
            arguments = listOf(navArgument("task") { type = NavType.StringType})
        ) { backStackEntry ->
            val obj = strToNCMBObject(backStackEntry.arguments!!.getString("task")!!, className)
            FormScreen(navController, obj)
        }
    }
}

タスクの登録

タスクの登録と編集は FormScreen にて行います。ナビゲーションから新規登録の場合は空のNCMBObject(クラス名はTask)、編集時には対象となるNCMBObjectを受け取ります。 objectId の有無によって、タスクのタイトルと本文のデフォルト値を変えています。

fun FormScreen(navController: NavController, obj: NCMBObject) {
    val objectId = obj.getObjectId()
		// タスクのタイトルと本文用
    var title by remember { mutableStateOf(if (objectId != null) obj.getString("title")!! else "") }
    var body by remember { mutableStateOf(if (objectId != null) obj.getString("body")!! else "") }
		// UIのヘッダーラベル
    val header = if (title == "") "新規作成" else "編集"
		// 保存処理中に立てるフラグ
    var progress by remember { mutableStateOf(false) }
		// アラートを表示する際のフラグ
    var showDialog by remember { mutableStateOf(false) }
		// アラートのメッセージ
    var message by remember { mutableStateOf("") }
		// アラート表示用
    if (showDialog) {
        AlertDialog(
            onDismissRequest = {},
            buttons = {
                Button(onClick = {
                    showDialog = false
                }) {
                    Text("OK")
                }
            },
            title = { Text("タスク保存") },
            text = { Text(message) }
        )
    }
		// 保存処理(後述)
    val save = {
    }
    Scaffold(
        topBar = {
            TopAppBar(
                title = {
                    Text("タスクの${header}")
                },
                actions = {
                    IconButton(
                        onClick = {
                        }
                    ){
                        Icon(Icons.Filled.Save, contentDescription = "Save")
                    }
                }
            )
        },
        content = {
            Column {
                OutlinedTextField(
                    value = title,
                    onValueChange = {
                        Log.d("INFO", it)
                        title = it
                                    },
                    modifier = Modifier.padding(20.dp),
                    label = { Text("タスクのタイトル") },
                    singleLine = true
                )
                OutlinedTextField(
                    value = body,
                    onValueChange = { body = it },
                    modifier = Modifier.padding(20.dp).height(150.dp),
                    label = { Text("タスクの本文") },
                    )
                Button(onClick = save,
                    enabled = !progress,
                    modifier = Modifier.padding(20.dp)
                ) {
                    if (progress) {
                        CircularProgressIndicator(
                            strokeWidth = 2.dp,
                            modifier = Modifier.size(24.dp)
                        )
                    } else {
                        Text("保存する")
                    }
                }
            }
        }
    )
}

Screenshot_20220414_155917.png

保存処理

保存処理は以下のようになります。 progress のフラグを立てて、二重処理を防止しています。入力されたタスクのタイトルと本文を設定し、保存を行います。保存後はナビゲーションで一覧へ戻ります。

val save = {
		progress = true
		try {
				// 入力値の設定
				obj.put("title", title)
				obj.put("body", body)
				// 保存
				obj.save()
				// 一覧画面に遷移
				navController.navigate("list")
		} catch(e: NCMBException){
				message = "タスクが保存できませんでした"
				showDialog = true
		}
		progress = false
}

まとめ

今回はタスクデータの保存について解説しました。次回はタスクデータの検索と一覧表示について解説します。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?