KotlinでAPI通信を行う
Kotlinを勉強し始めたばかりで間違い等ありましたら、御指摘して頂けますと幸いです。
APIを初めて叩くため、とりあえず表示させることだけを目的に書きました。
*ライブラリについては今回は記述しておりません。
*勉強のため非推奨のAPIを使っております。(後に改善予定)
PokeAPIを使う
今回はPokeAPIを使用してデータを取得します。
PokeAPI
レスポンスを受け取る型を定義
今回は『名前』『画像』を取得するための型を定義しました。
@SerializedName("front_default")
はGsonなどのJSONライブラリを使って、JSONデータから Kotlin のオブジェクトに変換するときのマッピングのルールを定義しています。
data class PokemonResponse(
val name: String,
val sprites: Sprites
)
data class Sprites (
@SerializedName("front_default")
val frontDefault: String?
)
interfaceを定義
PokeAPIの『interface』を定義します。
@GET("pokemon/{id}")
でHTTPのGETリクエストが使われ、『suspend』を使った関数はコルーチン内で非同期に呼び出されます。
@Path("id") id: Int
で指定したポケモンのURLの{id}に差し込まれ、このURLで返ってきたレスポンスのJSONをパースし『PokemonResponse型』のオブジェクトとして返します。
interface PokeAPIService {
@GET("pokemon/{id}")
suspend fun getPokemon(@Path("id") id: Int): PokemonResponse
}
APIにリクエストを送って、レスポンスとしてデータを取得するインスタンスを作成する
『object』を使用してシングルトンのインスタンスを生成します。
上記で作成した『PokeAPIService』のinterfaceに基づくAPIクライアントの実装を生成します。
val api: PokeAPIService by lazy { ... }
このプロパティは初めてアクセスされたときに、初期化されます。『by lazy』を使用することで、不要なタイミングでインスタンスが生成されず、リソースの無駄を防いでいます。
Retrofit
・・・HTTP通信を簡単に行うためのライブラリ。
object RetrofitInstance {
val api: PokeAPIService by lazy {
Retrofit.Builder()
.baseUrl("https://pokeapi.co/api/v2/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(PokeAPIService::class.java)
}
}
現段階では『MainActivity』の『onCreate』内でシンプルにAPI通信を実行しています。
lifecycleScope.launch {
for (id in 1..10) {
try {
//◆下記で1~10のIDのポケモンのデータを取得しpokemonListの配列に追加しています。
val pokemon = RetrofitInstance.api.getPokemon(id)
pokemonList.add(pokemon)
adapter.notifyItemInserted(pokemonList.size - 1)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
全体
class MainActivity : AppCompatActivity() {
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: PokeAPIListAdapter
private val pokemonList = mutableListOf<PokemonResponse>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window,true)
setContentView(R.layout.activity_main)
recyclerView = findViewById(R.id.pokeRecyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
adapter = PokeAPIListAdapter(pokemonList)
recyclerView.adapter = adapter
lifecycleScope.launch {
for (id in 1..10) {
try {
val pokemon = RetrofitInstance.api.getPokemon(id)
pokemonList.add(pokemon)
adapter.notifyItemInserted(pokemonList.size - 1)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
}
class PokeAPIListAdapter(private val pokemonList: MutableList<PokemonResponse>): RecyclerView.Adapter<PokeAPIListAdapter.ViewHolder>() {
class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
val pokeName: TextView = view.findViewById(R.id.textView)
val pokemonImage: ImageView = view.findViewById(R.id.imageView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val pokeText = LayoutInflater.from(parent.context)
.inflate(R.layout.pokemon_row, parent, false)
return ViewHolder(pokeText)
}
override fun getItemCount(): Int = pokemonList.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val pokemon = pokemonList[position]
holder.pokeName.text = pokemon.name
Glide.with(holder.itemView.context)
.load(pokemon.sprites.frontDefault)
.into(holder.pokemonImage)
}
}
data class PokemonResponse(
val name: String,
val sprites: Sprites
)
data class Sprites (
@SerializedName("front_default")
val frontDefault: String?
)
interface PokeAPIService {
@GET("pokemon/{id}")
suspend fun getPokemon(@Path("id") id: Int): PokemonResponse
}
object RetrofitInstance {
val api: PokeAPIService by lazy {
Retrofit.Builder()
.baseUrl("https://pokeapi.co/api/v2/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(PokeAPIService::class.java)
}
}
Discussion