こちらと同じことを行ってみました。
KotlinとRetrofitを使った初めてのAndroidアプリ開発
プロジェクトの作成
プロジェクト名: weather01
環境設定
(省略)
<uses-permission android:name="android.permission.INTERNET" />
(省略)
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
}
android {
namespace = "com.example.weather01"
compileSdk = 34
defaultConfig {
applicationId = "com.example.weather01"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.10.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
// androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// Retrofit
val retrofit_version = "2.9.0"
implementation("com.squareup.retrofit2:retrofit:$retrofit_version")
implementation("com.squareup.retrofit2:converter-moshi:$retrofit_version")
// Moshi
val moshi_version = "1.14.0"
implementation("com.squareup.moshi:moshi:$moshi_version")
implementation("com.squareup.moshi:moshi-kotlin:$moshi_version")
// Glide
val glide_version = "4.16.0"
implementation("com.github.bumptech.glide:glide:$glide_version")
annotationProcessor("com.github.bumptech.glide:compiler:$glide_version")
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.1.2" apply false
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
}
buildscript {
dependencies {
classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1")
}
}
<resources>
<string name="app_name">weather01</string>
<string name="post_button">送信</string>
<string name="text_placeholder">CityName</string>
<string name="text_temp">温度</string>
<string name="description_weather_icon">Weather status icon</string>
</resources>
(省略)
android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=false
(省略)
OWM_API_KEY="********"
画面
<?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:id="@+id/linearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<EditText
android:id="@+id/cityName"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:autofillHints="no"
android:ems="10"
android:hint="@string/text_placeholder"
android:inputType="text"
tools:ignore="SpeakableTextPresentCheck,SpeakableTextPresentCheck,TextContrastCheck" />
<Button
android:id="@+id/postButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/post_button" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@+id/linearLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
android:paddingStart="0dp"
android:paddingEnd="8dp"
android:text="@string/text_temp"
android:textAlignment="textStart"
android:textSize="24sp" />
<TextView
android:id="@+id/tempText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:textAlignment="textEnd"
android:textSize="24sp"
tools:text="13" />
</LinearLayout>
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:contentDescription="@string/description_weather_icon"
app:layout_constraintBottom_toTopOf="@+id/linearLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout2"
tools:srcCompat="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>
プログラム
package com.example.weather01
data class WeatherInfo(
val coord: Coord,
val weather: List<Weather>,
val base: String,
val main: Main,
val visibility: Int,
val wind: Wind,
val clouds: All,
val dt: Int,
val sys: Sys,
val timezone: Int,
val id: Int,
val name: String,
val cod: Int
)
data class Coord(
val lon: Double,
val lat: Double
)
data class Weather(
val id: Int,
val main: String,
val description: String,
val icon: String
)
data class Main(
val temp: Double,
val feels_like: Double,
val temp_min: Double,
val temp_max: Double,
val pressure: Int,
val humidity: Int
)
data class Wind(
val speed: Double,
val deg: Int
)
data class All(
val all: Int
)
data class Sys(
val type: Int,
val id: Int,
val country: String,
val sunrise: Int,
val sunset: Int
)
package com.example.weather01
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query
interface WeatherService {
@GET("data/2.5/weather/")
fun fetchWeather(
@Query("q") cityName: String,
@Query("appid") apiKey: String,
@Query("units") units: String
): Call<WeatherInfo>
}
package com.example.weather01
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import kotlin.concurrent.thread
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val editCityNameText = findViewById<EditText>(R.id.cityName)
val postButton = findViewById<Button>(R.id.postButton)
postButton.setOnClickListener {
fetchApi(editCityNameText.text.toString(), "metric")
}
}
private fun fetchApi(cityName: String, units: String) {
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.openweathermap.org/")
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
val tempText = findViewById<TextView>(R.id.tempText)
thread {
try {
val service: WeatherService = retrofit.create(WeatherService::class.java)
val weatherApiResponse = service.fetchWeather(
cityName,
BuildConfig.OWM_API_KEY,
units
).execute().body()
?: throw IllegalStateException("bodyがnullだよ!")
Handler(Looper.getMainLooper()).post {
tempText.text = weatherApiResponse.main.temp.toString()
Log.d("response-weather", weatherApiResponse.toString())
}
} catch (e: Exception) {
Log.d("response-weather", "debug $e")
}
}
}
}
実行結果
確認したバージョン
Android Studio Giraffe | 2022.3.1 Patch 2
Build #AI-223.8836.35.2231.10811636, built on September 15, 2023
Runtime version: 17.0.6+0-17.0.6b829.9-10027231 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Linux 6.5.0-9-generic
GC: G1 Young Generation, G1 Old Generation
Memory: 2048M
Cores: 12
Registry:
external.system.auto.import.disabled=true
debugger.new.tool.window.layout=true
ide.text.editor.with.preview.show.floating.toolbar=false
ide.experimental.ui=true
Current Desktop: ubuntu:GNOME