1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

NCMBのKotlin SDKを使って地図検索アプリを作る(その2:位置情報をインポートする)

1
Last updated at Posted at 2023-03-17

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を使って地図検索アプリを作ってみます。前回は画面の仕様とSDKの初期化について解説しました。今回は位置情報をデータストアにインポートする流れを解説します。

完成版のコード

作成したデモアプリのコードはNCMBMania/kotlin-map-searchにアップロードしてあります。

インポート画面について

インポート画面はMapBottomNavigationのタブで読み込まれています。 ImportScreen がそうです。

NavHost(navController = navController, startDestination = "Map") {
    composable("Map") { MapScreen()}
    composable("Import") { ImportScreen()}
}

インポート画面の構築

まず ImportScreen では文字列の配列が入る logs を mutableStateListOf で用意します。

@Composable
fun ImportScreen() {
    // ログメッセージ用
    var logs = remember { mutableStateListOf<String>() }

UIは次のようになります。インポート実行タンをタップすると、既存データの削除と駅情報を追加します。

Column(
    modifier = Modifier.fillMaxSize(),
    horizontalAlignment = Alignment.CenterHorizontally
) {
    Spacer(Modifier.size(20.dp))
    Button(
        onClick = {
            // 既存データの削除
            deleteAllStations()
            // JSONに入っている駅情報をNCMBのデータストアに保存
            for (i in 0 until stationsJson.length()) {
                val str = saveStation(stationsJson.getJSONObject(i))
                logs.add(str)
            }
        }
    ){
        Text(text = "山手線データをインポートする")
    }
    LazyColumn(
    ) {
        items(logs) { str ->
            Text(text = str)
        }
    }
}

データのインポートについて

データをインポートする際には繰り返し処理できるように、まず既存データを削除しています。もし既存データがなかった場合でも(データストアのクラスがなくとも)エラーにはならず、空の配列が返ってくるだけです。

// 既存データの削除
deleteAllStations()
// JSONに入っている駅情報をNCMBのデータストアに保存
for (i in 0 until stationsJson.length()) {
    val str = saveAllStations(stationsJson.getJSONObject(i))
    logs.add(str)
}

deleteAllStations は以下のようになります。NCMBQueryを使ってデータを取得し、各データ(NCMBObject)のdeleteInBackgroundメソッドを使ってデータを削除します。 delete もありますが、同期処理なので時間がかかってしまいます。

// 既存のデータを削除する処理
fun deleteAllStations() {
    // 検索対象のNCMBのデータストアクラス
    val query = NCMBQuery.forObject("Station")
    query.limit = 1000 // マックスまで指定しておく
    // 検索は同期で
    val stations = query.find()
    // 削除は非同期で終わらせる
    stations.forEach{
        it.deleteInBackground(NCMBCallback { e, _ ->
        })
    }
}

データを削除したら、山手線の各駅の位置情報が入ったJSONファイルの内容をデータストアに反映します。

// JSONに入っている駅情報をNCMBのデータストアに保存
for (i in 0 until stationsJson.length()) {
    val str = saveStation(stationsJson.getJSONObject(i))
    logs.add(str)
}

この時利用しているJSONは下記のようになっています。

struct Station {
    var name: String
    var latitude: Double
    var longitude: Double
}

読み込んだデータをデータストアに登録する registerDataStore 関数は以下のようになります。JSONファイルのパラメータを渡して、Stationクラスにデータを作成します。NCMBGeoPointを使って位置情報を保存するのがポイントです。こちらも保存を非同期にして高速化させています。

// 駅情報を保存する処理
fun saveStation(json: JSONObject ): String {
    // 位置情報からNCMBGeoPointを作成
    val geo = NCMBGeoPoint(latitude = json.getDouble("latitude"), longitude = json.getDouble("longitude"))
    // データストアのインスタンスを作成
    val station = NCMBObject("Station")
    // 駅名と位置情報をセット
    station.put("geo", geo)
    station.put("name", json.getString("name"))
    // 保存(量が多いので非同期で)
    station.saveInBackground(NCMBCallback {e, _ ->

    })
    return "${station.getString("name")}を取り込みました"
}

全体のコード

ImportScreenの内容は次のようになります。

@Composable
fun ImportScreen() {
    // ログメッセージ用
    var logs = remember { mutableStateListOf<String>() }

    // 山手線のJSONデータを読み込む処理
    val context = LocalContext.current
    var inputStream = context.assets.open("yamanote.json")
    val json = BufferedReader(InputStreamReader(inputStream)).readText()
    val stationsJson = JSONArray(json)

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Spacer(Modifier.size(20.dp))
        Button(
            onClick = {
                // 既存データの削除
                deleteAllStations()
                // JSONに入っている駅情報をNCMBのデータストアに保存
                for (i in 0 until stationsJson.length()) {
                    val str = saveStation(stationsJson.getJSONObject(i))
                    logs.add(str)
                }
            }
        ){
            Text(text = "山手線データをインポートする")
        }
        LazyColumn(
        ) {
            items(logs) { str ->
                Text(text = str)
            }
        }
    }
}

// 既存のデータを削除する処理
fun deleteAllStations() {
    // 検索対象のNCMBのデータストアクラス
    val query = NCMBQuery.forObject("Station")
    query.limit = 1000 // マックスまで指定しておく
    // 検索は同期で
    val stations = query.find()
    // 削除は非同期で終わらせる
    stations.forEach{
        it.deleteInBackground(NCMBCallback { e, _ ->
        })
    }
}

// 駅情報を保存する処理
fun saveStation(json: JSONObject ): String {
    // 位置情報からNCMBGeoPointを作成
    val geo = NCMBGeoPoint(latitude = json.getDouble("latitude"), longitude = json.getDouble("longitude"))
    // データストアのインスタンスを作成
    val station = NCMBObject("Station")
    // 駅名と位置情報をセット
    station.put("geo", geo)
    station.put("name", json.getString("name"))
    // 保存(量が多いので非同期で)
    station.saveInBackground(NCMBCallback {e, _ ->

    })
    return "${station.getString("name")}を取り込みました"
}

まとめ

今回はJSONファイルをインポートし、それを使ってNCMBObjectを作成しました。次回は地図コンポーネントと合わせて、位置情報検索を実装します。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?