[Android]Retrofitって、なんか名前かっこいいから、なんか分からないけど使ってみたい(ゆるく解説)


Retrofitって何?

どうもReoです。
Retrofitとは、API通信ができるライブラリです。
API通信とは、自分のスマホからサーバと通信して適当な情報を取ってくることです。
図式化するとこんな感じ。。

※実際にはお金は貰えないので注意

ライブラリは、既に先人によって作られた便利な部品みたいなもの。
つまり、Retrofitという部品をお借りしてAPI通信をします。

そして、例としてこちらのNewsAPIを使い、Top business headlines in the US right now(サイト内参照)を取得する処理を書きたいと思います。

サイト
https://newsapi.org/
取得する情報
https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey="取得したApiKey"

使い方

導入

まずは、こちらのリンク(https://newsapi.org/)
に入り、Get Startというボタンを押して、メールアドレス等入力するとAPIキーを取得できると思います。そちらが、今回のAPI通信で必要になるものです。
お次は、AndroidStudioでRetrofitを使えるようにします。
まず、build.gradle(:app)を開きます。
そして、dependencies{}内に以下を追加。

  def retrofit2_version = "2.5.0"
    implementation "com.squareup.retrofit2:retrofit:$retrofit2_version"
    implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit2_version"
    implementation "com.squareup.retrofit2:converter-gson:2.9.0"

  // ついでにこいつも
    def moshi_version = "1.5.0"
    implementation "com.squareup.moshi:moshi:$moshi_version"
    implementation "com.squareup.moshi:moshi-kotlin:$moshi_version"
    implementation "com.squareup.retrofit2:converter-moshi:2.9.0"

  // 非同期処理をするために必要(使うときに解説)
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'

ついでに追加したものは、Moshiといって、JSONをJavaオブジェクトに変換してくれる便利な奴です。
今回API通信で受け取る情報はJSONファイルという形式で受け取るのですが、それをこう、、、使えるようにするには変換しないといけないのです。
(筆者も良く分かってないw)
その為に、Moshiを使います!!!
追加した後は、Sync nowしてくださいね!

①ちょーだい(する情報)

サーバに情報をちょーだいするための指示を作る必要があります。
まず、その前に今回ちょーだいする情報はこちらです。

{
"status": "ok",
"totalResults": 70,
-"articles": [
-{
-"source": {
"id": null,
"name": "CNBC"
},
"author": "Elliot Smith",
"title": "Deutsche Bank reports its best quarterly profit since the first quarter of 2014 - CNBC",
"description": "Deutsche Bank on Wednesday reported a 908 million euro ($1.1 billion) profit for the first quarter, buoyed by continued strong performance in its investment banking division.",
"url": "https://www.cnbc.com/2021/04/28/deutsche-bank-earnings-q1-2021.html",
"urlToImage": "https://image.cnbcfm.com/api/v1/image/105343415-1532101496379gettyimages-975924044.jpeg?v=1553790495",
"publishedAt": "2021-04-28T05:16:43Z",
"content": "LONDON Deutsche Bank on Wednesday reported a 908 million euro ($1.1 billion) profit for the first quarter, buoyed by continued strong performance in its investment banking division.\r\nThe bank vastly … [+2839 chars]"
},

以下省略…

先程も触れました、JSON形式と呼ばれる情報の書き方で書かれているので、???とされたかもしれませんが、怖がらなくていいですよ!
書き方としては、変数名 : "値",となっています。
[]は、リストのことです。
articleというリスト型の変数名の中に、idは、nullという値が。
また、nameという変数には、"CNBC" という文字列が。
飛ばして、urlToImage(ネット上にある画像リンク)という変数には、"http://..(省略)" という文字列が。
publishedAtは、そのニュース記事が投稿された日。
contentは、ニュース記事内容。
このように、考えると何となく情報がニュース情報であり、形式も読み解けるはずです。
はずです…

①ちょーだい(する指示)

interface ApiService {
    @GET("/v2/top-headlines")
    suspend fun getNews(
        @Query("apiKey") apiKey: String,
        @Query("country") country: String
    ): Response<ResponseData>
}

新しいファイルを作成し、interfaceにて上記のように書きます。
@GETは、エンドポイントを指定します。
エンドポイントというのは、取得する情報の所在位置です。
最初の図式化に付け加えるとこんな感じ。

先程のイラストにてお金が、どこにあるのか?を示すのがエンドポイント、という風に捉えてください。
※飽くまでも比喩なので悪しからずw、サーバーの中に金庫的な概念はあるかどうかは分かりませんw
今回は、/v2/top-headlinesというパス(ファイルの場所)に目当てのお金…、いや情報があるということです。

そして、お次、suspend fun getNewsについて
fun getNewsはいいですね。メソッドを宣言しています。
そして、このメソッドなのですが非同期処理で呼び出さないといけません。

非同期について世界一分かりやすい記事
https://wa3.i-3-i.info/word1623.html

そして、導入の最後で追加したCoroutines(こちらが非同期処理を行ってくれる便利な奴です。)に対応させるためにsuspendを接頭語に加えているわけです。

そして@Queryについて、こちらはクエリパラメータと言います。

クエリパラメータについての分かりやすい記事
https://webtan.impress.co.jp/e/2012/04/26/12663

最初に取得する情報として、下記のURLを掲載しました。これを分析してみましょう。
https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey="取得したApiKey"

https://
こちらは、今回のAPI通信における、通信手段のことです。
つまり、https(httpとsslが融合した暗号化通信の事、分からなくても大丈夫)という通信手段を使うという意味です。

newsapi
こちらは、ホスト名です。
この名前のコンピュータから情報を取得しようとしています。

.org
こちらは、ドメイン名です。
newsapiというコンピュータが、ネット上のどこにあるのかを人に分かりやすいようにしたものです。

/v2/top-headlines
こちらは、パスです。
v2というフォルダの中に、top-headlinesというファイルが入っていることを示しています。

?country=us&category=business&apiKey="取得したApiKey"
それ以降がお待たせ登場、クエリパラメータ!
前述したJSONと同じように、?変数名=値という形式です。
&は、複数のクエリパラメータを続けて書く時に用います。
つまり、country、category、apiKeyの三つあります。

こちらは、検索条件の役割を果たしています。
呼び出す時には、@apiKeyには、自分で取得したapiKeyをセットし、@countryには、jpをセットします。(これで、日本のニュースが取得する操作が出来るはずです。)

そして、Response(型はResponseData)というリストで返します。
※ResponseDataは、後述。

①ちょーだい(を保持する場所)

data class ResponseData(
    val url: String,
    val urlToImage: String,
    val publishedAt: String,
    val content: String
)

こちらは、サーバから頂いた情報を保持するデータクラスと呼ばれるものです。
図式化するとこんな感じ。

①ちょーだい(してみる)

private var response: Response<ResponseData>? = null

(省略)

 val newsService = Retrofit.Builder()
            .baseUrl("https://newsapi.org/")
            .addConverterFactory(MoshiConverterFactory.create())
            .build()
            .create(ApiService::class.java)
        GlobalScope.launch(Dispatchers.IO) {
            response = newsService.getNews("api_key", "jp")
            if (response!!.isSuccessful) {
                val article = response!!.body()
                Log.d("debug", article.toString())
            }

本当は、ViewでAPI叩くの良くないのです。
MVVM化した記事を書きたい反面、まだ理解が浅いので今回だけ許して~!
とはいえ、今回の趣旨はRetrofitを使うことなので!
Retrofitを用いて、API叩く処理は次のように書きます。
baseUrlには、スキームからドメイン名をセット。
addConverterFactoryには、最初に説明したMoshiをセット。
crateには、①ちょーだい(する指示)にて作成したApiServiceをセット。

また、GloalScope.launch(Dispathers.IO) {}ですが、この中で非同期処理を書くことが出来ます。
getNewsのパラメータには、取得したApiKeyとjpをセット。

そして、本来はエラーハンドリングすべきなのですが省略。。。。

取得した情報を受けている、response。
if文にて、response.isSuccessfulで、データ取得に成功したら、response.!!body() = articleで中身を確認できます。

Logcatにて、

こんな感じのデータが、表示していれば無事終了です!

終わりに

取り敢えず、1週間前は自力でAPI叩くの無謀な取り組みだと思っていましたが、何とか実装し記事を書けるまで完了できました。ただ、ViewでAPI叩いたり、!!を用いているたりとコード自体は決してきれいなものではありません。それが、これから学びたいことだなと思いました。
プリンシパルプログラミングでも読むか~!(終)