kotlin android (retrofit2 + gson + list_view)

アプリを作ることになったのだが、とりあえず練習がてら何かのApiを叩いてJSONをパースしてlistを表示できればOKだったので、qiitaのApiを叩いて表示してみました。

Android studio 3.2.1を使って開発しましたが、android開発は初めてなのでこれでいいのかよくわからず…
[githubはこちら](https://github.com/okbm/qiita_android_app)

完成後のスクショ
<img src="https://qiita-image-store.s3.amazonaws.com/0/10333/b5775889-0ae0-d219-b6ab-46db1d9766b5.png" width="320px">

## ライブラリなど

```build.gradle
    def retrofitVersion = '2.4.0'
    implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
    implementation "com.squareup.retrofit2:adapter-rxjava:$retrofitVersion"
    implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"
    implementation 'com.squareup.okhttp3:logging-interceptor:3.8.1'
```

デバッグ時のloggerがあるとすごく開発が捗るので入れてよかったです。

```app/src/main/AndroidManifest.xml
+    <uses-permission android:name="android.permission.INTERNET" />
```

これをいれないとApiをたたけないです

## modelなど

```models/item.kt
data class Item(var id: String,
                var title: String,
                var url: String)
```

```Interfaces/ItemInterface.kt
import retrofit2.http.GET
import retrofit2.Call
import retrofit2.Retrofit
import ml.okbm.qiita_app.models.Item
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.converter.gson.GsonConverterFactory

interface ItemInterface {
    @GET("v2/items.json")
    fun items(): Call<List<Item>>
}

fun createService(): ItemInterface {
    val baseApiUrl = "https://qiita.com/api/"

    val httpLogging = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
    val httpClientBuilder = OkHttpClient.Builder().addInterceptor(httpLogging)

    val retrofit = Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl(baseApiUrl)
        .client(httpClientBuilder.build())
        .build()

    return retrofit.create(ItemInterface::class.java)
}
```

tokenを使った認証をしていないので、1時間に60回しか叩けません。  
[Qiita API v2ドキュメント - Qiita:Developer](https://qiita.com/api/v2/docs)に詳しく書いてます。

```MainActivity
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import ml.okbm.qiita_app.Interfaces.createService
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import android.util.Log
import android.widget.ArrayAdapter
import android.widget.ListView

class MainActivity : AppCompatActivity() {

    // interfaceという名前微妙だがサンプルなので我慢
    private val itemInterface by lazy { createService() }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        fetchItems()
    }

    private fun fetchItems() {

        itemInterface.items().enqueue(object : Callback<List<Item>> {
            override fun onFailure(call: Call<List<Item>>?, t: Throwable?) {
                Log.d("fetchItems", "response fail")
                Log.d("fetchItems", "throwable :$t")
            }

            override fun onResponse(call: Call<List<Item>>?, response: Response<List<Item>>) {
                if (response.isSuccessful) {
                    response.body()?.let {
                        Log.d("fetchItems", "response success")
                        var items = mutableListOf<String>()

                        for (item in it) {
                            items.add(item.title)
                        }

                        val adapter = ArrayAdapter<String>(this@MainActivity, android.R.layout.simple_list_item_1, items)
                        val list: ListView = findViewById(R.id.list_item);
                        list.adapter  = adapter
                    }
                }
                Log.d("fetchItems", "response code:" + response.code())
                Log.d("fetchItems", "response errorBody:" + response.errorBody())
           }
        })
    }
}
```

apiのレスポンスが以下のようになっているため、responseを`<List<Item>>`にしています。

```
[
  {
     "response_body": xxx,
     "id: xxx,
  }
]
```

また結構ログを入れたままにしているのは確認のためなので、必要なかったら切ってもらってもいいかもですね。
最初reuqestしてるURLを見たかったので入れてて便利だったのでそのまま残しちゃいましたが。。。

listはもっと凝った作りにして、DataBindingを使ったやり方にしないとだめそうなんだけど、一旦ここで終わり。

## 参考リンク

- [Android Kotlin で Retrofit2 を使って Web API JSON処理 - グロブ](http://typea.info/blg/glob/2018/07/android-kotlin-retrofit2-web-api-json.html)
- [Retrofit2 + Kotlin + 楽天商品検索APIを用いて検索結果をAndroidアプリに表示してみる - zukkeyの技術奮闘記](http://rozkey.hatenablog.com/entry/2018/03/21/205703)
- [Android Retrofit2 with Kotlin - Qiita](https://qiita.com/SYABU555/items/3b280a8e81d2cc897383)
- [Retrofit 2で使うBacklog APIとは--Kotlinで作るAndroidアプリの場合 | ヌーラボ](https://nulab-inc.com/ja/blog/backlog/retrofit2-backlog-api/)