AndroidでAPIから情報をゲットしてみよう
この記事はあくあたん工房クリスマスアドベントカレンダー22日目の記事です.
はじめに
最近Androidアプリ開発の勉強をしているのですが,WebAPIを使ってみたくなったので今回はTwitterAPIで指定した単語を含むツイートを検索して遊んでみようと思います.
環境
- Mac OS Catalina 10.15.7
- Android Studio 4.1
- kotlin plugin 1.3.72
- APIレベル 26 Android8.0
Twitter APIへアクセスするための各種キーの取得
Twitter APIの使用申請
Twitter APIを使用するには使用のために申請をする必要があります. 詳しくは以下の記事等を参考にしてみてください.
2020年度版 Twitter API利用申請の例文からAPIキーの取得まで詳しく解説 | 新宿のホームページ制作会社 ITTI(イッティ)
申請の返事はだいたい1日か2日で返ってきたと思います.
Twitter APIの各種キーを保存
申請が通るとAPI key
とAPI key secret
,Bearer token
というものがもらえます.
API keyとsecretはあとから確認できるのですが,Bearer tokenは確認できないので(再生成はできる)しっかり保存しておきましょう.
ツイートやリツイートなどの機能以外はこのBearer tokenのみで行うことができます.
最初にやること
マニフェストファイルにインターネット使用のパーミッションを設定
これがないと通信してデータを持ってくるみたいなことができません.
以下の1文をapp/src/main/AndroidManifest.xml
に追記してください.
<uses-permission android:name="android.permission.INTERNET"/>
APIから情報を得るためのライブラリを導入
- Retrofit:APIコールを簡単に行ためのツール
- coroutine:実行スレッドを分けて並列処理するための仕組み
app/build.gradle
のdependences
に以下を追記してください.
implementation 'com.squareup.retrofit2:retrofit:2.7.1' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
コードを書いていく
APIを使用するためのinterfaceを実装
今回使用するエンドポイントはhttps://api.twitter.com/2/tweets/search/recent?query=
なので,そこをGET
で叩くように作ります.
Twitter APIを叩くためには認証情報が必要なのでヘッダに指定してあげます. また,検索したい単語を指定するためにqueryを入れるようにしておきます.
package com.example.adventcalendar import okhttp3.ResponseBody import retrofit2.http.GET import retrofit2.http.Header import retrofit2.http.Query interface TwitterApi { @GET("search/recent") suspend fun fetchTweets( @Header("Authorization") accessToken: String, @Query("query") searchWord: String? = null ):ResponseBody }
これでfetchTweets()
にトークンとクエリを入れて実行してあげることでAPIからレスポンスが返ってきます.
画面を作る
今回は任意の単語をクエリとしてAPIのレスポンスを受け取るだけなので,単語を入力するEditText
とButton
だけ追加します.
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <EditText android:id="@+id/edit" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Get API response!"/> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAlignment="center" android:text="Response here" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
処理部分を作る
Retrofitを設定して作成したAPIをインスタンス化する
今回は簡単に作るために認証トークンを直に書いていますが,もしGitHubなどで管理する場合はhoge.properties
などに書いてBuildConfig
で参照するようにしましょう.
private val BEARER_TOKEN = "************" private val BASE_URL = "https://api.twitter.com/2/tweets/" private val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .build() private val api = retrofit.create(TwitterApi::class.java)
Coroutineについて
ここで,一旦話が逸れるのですが,Coroutineについて説明します.
Androidアプリでは,Main
スレッドで画面の更新などの処理を行っているため,時間がかかる処理をMain
スレッドで行ってしまうと,それが終わるまで画面が更新できません.
そのため,時間がかかる処理は別スレッドで行わなければいけないことになっており,ネットからデータを持ってくる処理は遅くなる可能性が高いので,別スレッドで処理を行う必要があります.
そこで利用されるのがCoroutineです. Coroutineを利用して別スレッドに処理させることで上記の問題を解決します.
使い方は簡単で,CoroutineScope()
の引数として処理させたいスレッドを指定し,.launch
内に処理を書きます.
今回はIO
スレッドにAPIからデータを取得する処理をしてもらいましょう.
CoroutineScope(Dispatchers.IO).launch {
// APIからデータを取得する処理
}
さて,APIから取得したデータをTextView
に反映したいのですが,ここで一つ問題が生じます.
CoroutineScope
内で定義した値は同スコープ内でしか使えないため,同スコープ内にTextView
の書き換え処理を書く必要があります.
しかし,Main
スレッド以外で画面の更新をするとエラーになってしまいます.
このような,「あるスレッドのCoroutineScope
内で別スレッドを動かしたい」となったときに使うのがwithContext()
です.
CoroutineScope(Dispatchers.IO).launch { // APIからデータを取得する処理 withContext(Dispatchers.Main) { // 取得したデータで画面を更新する処理 } }
ボタンを押したときの挙動を定義
話を実装の方に戻します.
ボタンのListenerを以下のようにonCreate()
内に定義します.
val button = findViewById<Button>(R.id.button) val textBox = findViewById<EditText>(R.id.edit) val textView = findViewById<TextView>(R.id.text) button.setOnClickListener{ val query = textBox.text.toString() CoroutineScope(Dispatchers.IO).launch { val response = api.fetchTweets(accessToken = "Bearer $BEARER_TOKEN", searchWord = query).string() withContext(Dispatchers.Main) { textView.text = response } } }
完成
実行してみるとこんな感じ.
ちゃんとレスポンスが返ってきてTextView
が更新されていますね.
さいごに
今回はkotlinで書いたAndroidアプリでTwitter APIから情報を取得するまでの流れを紹介しました.
取得した情報を実際に使うときはレスポンスのjsonをパースしていい感じに表示するのですが,かなり長くなってしまうので今回は取得部分までとしました.気が向いたらパースしてList表示する部分を書くかもしれません.
Web APIが使えるようになると作れるものの幅がグッと広がるので,ぜひ皆さんも試してみてください!