こんにちはmotochikaです。
1ヶ月ほど前から趣味でKotlinの勉強をしています。
最近、HTTP通信を利用した簡単な天気アプリを便利なライブラリを使いながら作ったので記事にしてみました。
APIはLiveDoor天気情報のWeather Hacksです。
http://weather.livedoor.com/weather_hacks/webservice
*WeatherHacksは2020/7/31を以って終了してしまったそうです。
画面に表示された地域はほんの一例で、お天気APIに対応している地域ならどこでも表示できます。
##使用したライブラリ
####Retrofit2
APIをJava/Kotlinインターフェースに変換するライブリです。
公式
retrofit2とmoshiのコンバータを導入します。
implementation 'com.squareup.retrofit2:retrofit:retrofit2の現バージョン'
implementation 'com.squareup.retrofit2:converter-moshi:retrofit2の現バージョン'
####Moshi
Jsonのパースを行うライブラリです。
kotlinクラスへのサポートを提供しています。
公式
implementation "com.squareup.moshi:moshi:moshiの現バージョン"
implementation "com.squareup.moshi:moshi-adapters:moshiの現バージョン"
implementation "com.squareup.moshi:moshi-kotlin:moshiの現バージョン"
kapt "com.squareup.moshi:moshi-kotlin-codegen:moshiの現バージョン"
最後のkapt
ですがkotlin-annotation-processing toolsといって、アノテーションを使いコードを生成できるツールです。retrofit2を使う際に必要です。
apply plugin: 'kotlin-kapt'
最初にこう書いてあげることも忘れずに。
###内容
はじめにインターフェースを作成します。
import com.example.motochika.getweather.api.WeatherInfo
import retrofit2.http.GET
import retrofit2.http.Query
interface WeatherApi {
//"forecast/webservice/json/v1"にGETリクエストをする関数
@GET("/forecast/webservice/json/v1")
suspend fun getWeatherInfo(
@Query("city")
city: String
): WeatherInfo
}
Retrofit2では$@$GET(規定URL以降の部分)でGETリクエスト先のAPIを指定できます。
http://weather.livedoor.com/forecast/webservice/json/v1?city=400040
関数getWeatherInfo
では引数をリクエストに含めるパラメータとし、戻り値はJSONデータを受け取るデータクラスWeatherInfoとしています。
次のクラスApiFactory
では上記のインターフェースをインスタンス化して返す関数weatherApi
を定義しています。
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.create
class ApiFactory {
fun weatherApi(): WeatherApi {
val BASE_URL = "http://weather.livedoor.com"
val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val retrofit = Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
return retrofit.create(WeatherApi::class.java)
}
}
関数weatherApi
では生成したMoshiのインスタンスと規定URLを元にしてretrofitインスタンスを生成します。こうしてあるプログラムでApiFactory
のインスタンスを生成した際に関数weatherApi
を中継して先ほどの関数getWeatherInfo
を呼び出すことができます。
次のコードのwhen文の内部をみてください。
suspend fun getWeather(id: String, day: String) = withContext(Dispatchers.IO) {
val http = ApiFactory()
when (day) {
"今日" -> http.weatherApi().getWeaterInfo(id).forecasts.find {
it.dateLabel == "今日"
}?.telop
"明日" -> http.weatherApi().getWeaterInfo(id).forecasts.find {
it.dateLabel == "明日"
}?.telop
"明後日" -> http.weatherApi().getWeaterInfo(id).forecasts.find {
it.dateLabel == "明後日"
}?.telop
else -> "日なし"
}
}
suspend fun setWeatherText(day: String) {
weather_result.setText(
"札幌の${Day}の天気:" + setWeather("016010", Day) + "\n" +
"旭川の${day}の天気:" + getWeather("012010", day) + "\n" +
"函館の${day}の天気:" + getWeather("017010", day) + "\n" +
"仙台の${day}の天気:" + getWeather("040010", day) + "\n" +
"米沢の${day}の天気:" + getWeather("060020", day) + "\n" +
"新潟の${day}の天気:" + getWeather("150010", day) + "\n" +
"会津若松の${day}の天気:" + getWeather("070030", day) + "\n" +
"東京の${day}の天気:" + getWeather("130010", day) + "\n" +
"横浜の${day}の天気:" + getWeather("140010", day) + "\n" +
"名古屋の${day}の天気:" + getWeather("230010", day) + "\n" +
"大阪の${day}の天気:" + getWeather("270000", day) + "\n" +
"京都の${day}の天気:" + getWeather("260010", day) + "\n" +
"広島の${day}の天気:" + getWeather("340010", day) + "\n" +
"熊本の${day}の天気:" + getWeather("430010", day) + "\n"
)
}
}
関数getWeatherInfo
に地域idを投げるだけで、戻り値のデータクラスについて様々な処理ができます。そして関数getWeather
では地域idと今日〜明後日というキーワードを元に天気予報を返しています。
余談ですが weather_result.setText
について、weather_resultはTextViewのid名です。
kotlin-android-extensionsを使用すると、findViewById()を使わなくても直接id名が使えます。小さいことですがとても感動しました。
##最後に
こうして記事にすると自分で書いたコードでもまだ理解できていない場所が洗い出されるので、Qiitaに投稿するのはとても良いことだなぁと思いました。
サポートしてくれてありがとうございます。@yt8492