見出し画像

「COMPOSE を用いた ANDROID アプリ開発の基礎」の学習支援⑮ -ユニット5パスウェイ1

皆さん、こんにちは!又はこんばんは!初めての方は初めまして!
Google Codelabsの「COMPOSE を用いた ANDROID アプリ開発の基礎」コースのお手伝いをする「りおん」です。
今回は、ユニット5「インターネットに接続する」のパ
スウェイ1「インターネットからデータを取得する」です。

補足のため、「COMPOSE を用いた ANDROID アプリ開発の基礎」コースで心配になった時、エラーが起きて詰まった時や、分からないことがあった時、軽く復習したい時に見てください!
目次を見て、自分に必要なところだけ見るのをお勧めします!

この記事を作成するにあたり使用しているAndroid StudioのバージョンはGiraffeです。バージョンによってはUIが違うことがあるのでご了承ください。
また、2024年4月09日現在の「COMPOSE を用いた ANDROID アプリ開発の基礎」コースを参考にしています。


学習内容

②Kotlinのプレイグラウンドのコルーチン概要

ディスパッチャは実行に使用するスレッドを決定するものですが、ここでは分かりやすくするためにディスパッチャ=スレッドとしています

まずは、各用語間の関係です。下の図を参照してください。

用語の関係図

大前提として、我々は一度に複数のタスクを行うという"同時実行"がしたいというところから始まります。
同時実行を達成するには方法が大きく2つあります。
1.スレッドは1個のみで効率よく使用する
2.複数のスレッドを使用する。
1個のスレッドはある時刻において1個のタスクしかこなせない

1個のスレッドで効率よく複数のタスクをこなす方法として、1つのスレッドで非同期コードを書くという物があります。
1つの例として、タスクAは画面にUIを表示する、タスクBは10秒間の待機、タスクCは6秒間の待機とします。
このタスクを順次実行(=同期コードで書く)していたら16秒間ユーザーは画面操作出来ません。
しかし、非同期コードを用いると、タスクB,Cを中断してタスクAを行うことが出来ます。勿論、10秒間の待機という目的が達成された後タスクBに戻りますがここでは待機以外無いのですぐタスクAに戻ります。タスクCも同様です。

同期コードと非同期コード
非同期コードの詳細…一つのスレッド(棒)で効率よく仕事をこなしている

複数のスレッドを使用することは物理的にも複数のタスクを同時に行っているので効率がいいのは直感的にも理解できると思います。

スレッドが多いと複数の仕事を早く終わらせれる

コルーチンを用いたら、同時実行のための上記2種類の方法を組み合わせた「複数のスレッドを効率よく使用する」ことが出来ます

同時実行の身近な例は複数のソシャゲの周回です。
スレッドが1個の場合=スマホが1台の時は、
スタミナが切れるまであるソシャゲを周回します。
スタミナが切れたら、そのソシャゲを切って別のソシャゲを周回します。
そして、元のソシャゲのスタミナが溜まったら再開します。

ソシャゲの周回に例えた例(その1)

スレッドが複数個の場合=スマホが複数台の時は、
それぞれのスマホで別のソシャゲの周回を行います。

ソシャゲの周回に例えた例(その2)

そして、それらを組み合わせた最大効率が、複数のスマホでスタミナがあるソシャゲを周回するというものになります。
これには、心当たりがある方も多いと思います。

コルーチンのコンセプトで大事なのは、親がキャンセルされたらそれが子に伝わる、子のエラーは親に伝搬するの2つです。
今回のCodelabsでは子のエラーが親のジョブに伝わり、キャンセルされないようにするためcatch-try文を用いて例外処理を行いました。

③Android Studioのコルーチンの概要

コンポーザブル内部からsuspend関数を呼び出す方法として、LaunchedEffect()コンポーザブルを使用することを学習しました。
LaunchedEffect()コンポーザブルはコンポーザブルがコンポジション(≒HAS-A関係)に残っている限りsuspend関数を実行します。

LaunchedEffect内でコルーチンスコープを用いて同時実行をしている

また、コルーチンを単体テストする際は、テスト関数自体はsuspend関数でないためsuspend関数を呼び出せません。そのため、runTestコルーチンビルダーを使用し、新しいコルーチンを開始する必要があることを学びました。

⑤インターネットからデータを取得する

Restfulなウェブサービスと通信するためにRetrofitについて学習しました。
Retrofitとは、HTTPクライアントを実装するためのライブラリです。
イメージとしてはアプリ+Retrofitでクライアントになり、サーバ(RESTfulウェブサービスを実行している)と通信する感じです。
(もちろんRetrofitを使用せずともクライアントは実装出来ますが使用した方がAPIのエンドポイントの把握などの必要が無く楽です)
Retrofitを使用することでHTTPリクエストの作成、送信やレスポンスの受信のプロセスを簡略化できます。

Retrofitの概念図

この概念図を書くにあたって、Codelabsのほかに以下の記事も参考にしています。

Retrofitを使用しインターネット上のRest webサービスAPIに接続しレスポンスを取得する方法は以下の通りです。
1.Retrofitの依存関係の追加

//build.gradle.kts(Module:app)のpluginsブロック内に
id("org.jetbrains.kotlin.android") version "1.9.10" apply false
//build.gradle.kts(Module:app)のdependenciesセクションに
// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
// Retrofit with Kotlin serialization Converter
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
implementation("com.squareup.okhttp3:okhttp:4.11.0")

2.インターネット権限の追加

//manifests/AndroidManifest.xmlの<application>タグの直前に追加
<uses-permission android:name="android.permission.INTERNET" />

3.ウェブサービスのベースURLの定義

今回のアプリのバックエンドサーバーのURI

4.JSONレスポンスをマッピングするためのデータクラスを作成
@SerializableはMarsPhotoクラスをシリアル化可能にするために使用
@SerialNameはJSONレスポンスのキー名と違う変数名をデータクラスで使用しているため使用。

今回はid(文字列)とimg_src(文字列)で構成されるJSONレスポンスであるため、それを解析した結果を格納するデータクラスとしてMarsPhotoを作成

5.ベースURLとコンバータファクトリを使用しRetrofitオブジェクトの作成

kotlinx.serializationを用いてJSON文字列をKotlinオブジェクトに変換している

6.Retrofitがウェブサーバーと通信する方法を記述するインターフェースの作成

GETリクエストの為@GETを使用

7.Retrofitサービスを作成し、APIサービスのインスタンスをアプリのほかの部分に公開

今回はシングルトンパターンを使用(通常は推奨されていない)

用語

②Kotlinのプレイグラウンドのコルーチン概要

用語自体の説明はCodelabs内でされています。
用語間の関係は学習内容の方に図を描いているので参考にしてください。

⑤インターネットからデータを取得する

Retrofitについては学習内容のほうで説明していますので参考にしてください。

コンバータ

converterとは日本語訳すると変換器です。
Microsoft Learnの記事によると、

"コンバーター" は、オブジェクトまたは値を JSON との間で双方向に変換するクラスです。

「.NET で JSON シリアル化 (マーシャリング) のためのカスタム コンバーターを作成する方法」
https://learn.microsoft.com/ja-jp/dotnet/standard/serialization/system-text-json/converters-how-to?pivots=dotnet-8-0


注意事項

⑤インターネットからデータを取得する

kotlinx.serializationを使用した際のエラー(超重要)

エラー文は以下の通りです。
Process: com.example.marsphotos, PID: 13343
java.lang.IllegalArgumentException: Unable to create converter for java.util.List<com.example.marsphotos.network.MarsPhoto>
for method MarsApiService.getPhotos

エラー画面

解決法として、ライブラリの依存関係を変えてください

//変更前
id("org.jetbrains.kotlin.plugin.serialization") version "1.8.10"
//変更後
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10"

依存関係でエラーが起きるというのは結構見受けられます。
指示に従ったのにエラーが出る、何も間違っているはずがないのにエラーが出るという場合は解答コードに書かれている依存関係に変更してみてください。

さいごに

今回もCodelabsでの学習お疲れさまでした。
今回はRetrofitを用いてwebサーバにリクエストして、返ってきたJSONレスポンスをkotlinx.selializationで解析しkotlinオブジェクトに変換し、結果を画面上に表示するというものでした。
Retrofitは画像の読み込みをサポートしていなので、この内容だけでは画像のURLだけ取得のみで画像を表示することはできません。そこで次回はCoilライブラリを使用してURLから画像を表示する方法を学びます。
今回の内容は次回の内容とセットで活躍するので、是非次のCodelabsを学習してください!

この記事が気に入ったらサポートをしてみませんか?