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("保存する")
}
}
}
}
)
}
保存処理
保存処理は以下のようになります。 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
}
まとめ
今回はタスクデータの保存について解説しました。次回はタスクデータの検索と一覧表示について解説します。