kotlin: 非同期処理(http通信)で取得したデータをListViewに反映する。

プログラミング
スポンサーリンク




こんにちは、おみです。

先日、DBのデータをJSON形式で返すWebAPIを作成しました。

今回は、このAPIから取得したデータをListViewに表示する方法について、書きたいと思います。

https://moimoiblog.com/programing/python-easy-db-access-api/
スポンサーリンク

概要

今回使用するAPIは、

http://10.0.2.2:5000/get

にアクセスすると、JSONデータを返却するAPIです。(これ以降、下記のJSONが返却されたものとして進行します。)

[
{
"id": "1",
"name": "SQLを理解する"
},
{
"id": "2",
"name": "Flaskを理解する"
},
{
"id": "3",
"name": "鬼滅の刃20巻を買いに行く"
}
]

このAPIから取得したデータを、ListViewに格納していきます。

↓イメージ

kotlinにおけるHTTP通信とUIの扱いについて

kotlinには、下記のような制約があります。

  • HTTP通信は、メインスレッドで行ってはならない(非同期処理を行う必要がある)
  • UIの更新は、メインスレッドでのみ行うことができる。

つまり、APIから取得したデータをListViewに反映する場合、下記のような手順で更新を行う必要があります。

  1. 別スレッドでAPIへの接続を行う
  2. 1の処理が終わるまで待つ
  3. 取得したデータを元にListViewを更新する

事前準備

今回は、非同期通信を行うために、「coroutine」というライブラリを、JSONの解析を行うために「GSON」というライブラリを使用します。

どういうことですかものかについては、他サイト様をご覧ください。

gradleファイルに、下記の文言を追加して読み込みます。

dependencies {
    implementation 'com.google.code.gson:gson:2.8.6'
    def coroutines_version = '1.3.4'
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
}

ソースコード

MainActivity.tk

適用したいボタン.setOnClickListener {
    GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT) {
        // JSONデータを取得する
        val json_data = jsonGET("http://10.0.2.2:5000/get").await()

        // JSON→リストに格納する際に使用するオブジェクトを生成する
        val listType = object : TypeToken<List<RowData>>() {}.type

        // リストを生成する
        val list: List<RowData> = Gson().fromJson(json_data, listType)

        // ListViewにデータを追加
        listView.adapter = RowDataAdapter(this@MainActivity, list)
    }    
}

// APIにアクセスし、JSONデータを取得する
fun jsonGET(url: String): Deferred<String?> = GlobalScope.async {
    val triple = url.httpGet().response()
    return@async String(triple.second.data)
}

RowData.tk

data class RowData(val id: String, val name: String)

RowAdapter.tk

class RowDataAdapter(val context: Context, val list: List<RowData>) : BaseAdapter() {
val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater

override fun getCount(): Int {
return list.count()
}

override fun getItem(position: Int): RowData {
return list[position]
}

override fun getItemId(position: Int): Long {
return position.toLong()
}

@SuppressLint("ViewHolder", "SetTextI18n")
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view = layoutInflater.inflate(R.layout.rowdata, parent, false) //表示するレイアウト取得
val numtext = view.findViewById<TextView>(R.id.lbl_title)
numtext.text = list[position].name

return view
}
}

rowdata.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >

<TextView
android:id="@+id/lbl_title"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:textSize="10sp"
android:shadowRadius="10.0"/>

<Button
android:id="@+id/btn_favorite"
android:layout_width="0sp"
android:layout_height="match_parent"
android:layout_weight="0.2"
android:text="@string/btn_favorite"
android:textSize="30sp"/>
</LinearLayout>

strings.xml

<resources>
<string name="app_name">social_lexicon</string>
<string name="btn_favorite">○︎</string>
</resources>

参考文献

AndroidでKotlinのcoroutine(Async, Await)を使ってサクッとHTTP通信(非同期処理)を行う - Qiita
はじめに Kotlinを用いてAndroidアプリ開発を行っていて 「REST APIを叩いて取得した結果をもとにUIを更新する」際に HTTP通信はメインスレッド外で行う必要がある(非同期処理が必要) 取得したjsonデー...

コメント

タイトルとURLをコピーしました