本稿の趣旨
このCodeZineでAndroidの非同期処理に関しての記事を公開するのは、今回が初めてではありません。「Android Studio 2で始めるアプリ開発入門」連載の第11回で紹介しています。なぜ、このタイミングで、再度、非同期処理の話題を取り上げるのか、その経緯をまずお話しいたします。
お天気情報サービスの終了
「Android Studio 2で始めるアプリ開発入門」連載の第11回が公開されてから、すでに4年が経過しています。また、この連載をもとに加筆、再構成の上に書籍化した『基礎&応用力をしっかり育成! Androidアプリ開発の教科書』が刊行されてから3年弱が経過しました。同様に、この『基礎&応用力をしっかり育成! Androidアプリ開発の教科書』のKotlin対応版の刊行からは1年半経っています。
これらの時間が経過した間に、連載、両書籍に共通して利用してきたWeb APIであるライブドアのお天気情報サービスが、2020年7月末に終了しています。そのため、現状、サンプルソースコードが動作しなくなっています。
AsyncTaskが非推奨に
利用するWeb APIサービスが終了しただけならば、利用先を変更するだけで動作するようになります。もちろん、利用先に合わせて多少ソースコードの変更は出てきます。
それよりも、さらに重大な変化として、非同期処理コードの根幹として利用してきたAsyncTaskクラスが、2020年9月8日にリリースされたAndroid 11(APIレベル30)で非推奨となってしまいました。そのため、連載、書籍通して解説してきたソースコードの記述方法が、今後全く通用しなくなります。
これが本稿が公開されることになった経緯です。
AsyncTaskの代わり
非推奨となったAsyncTaskクラスの代わりとして、Androidの公式ドキュメントで推奨している方法は、Javaの標準パッケージであるjava.util.concurrentとKotlinコルーチンの利用です。そこで、本稿では、非同期処理の考え方を再度紹介するとともに、Javaの標準パッケージを利用した記述方法を、第1回、つまり、今回紹介します。第2回は、この続きとして、サービスが終了したライブドアのお天気情報サービスの代わりとして、Open WeatherのWeb APIサービスを利用しながら、AndroidでのHTTP通信の方法、および、JSONデータの処理方法を紹介します。第3回は、Kotlinコルーチンを利用した方法を紹介します。
非同期処理概観
ソースコードを交えての解説に先立ち、非同期処理とはどのようなものかをまず確認しておきましょう。
Java言語のメソッド連携は同期処理
非同期処理の話をする前に、Javaのメソッド連携について確認しておきましょう。図1を見てください。
この図は、Javaのメソッド連携とスレッドの関係を表しています。Javaで何かの処理が起動したとします。これをメイン処理とします。代表的なのは、main()メソッドを実行した場合でしょう。Javaでは、処理の一連の流れを「スレッド」という単位で扱っており、このメイン処理がひとつ開始されることで、スレッドがひとつ起動します。
そして、そのメイン処理から呼び出されるメソッドは、同じスレッド上で動作します。図1では、メイン処理が開始されてから次にcalcData()メソッドを呼び出し、その後、putData()メソッドを呼び出している様子を図式化しており、これら一連の処理の流れが全て同一スレッド上で実行されることを表しています。
ということは、メイン処理からcalcData()を呼び出した時点で、スレッドはcalcData()の実行に使われることになり、calcData()の処理が終了して初めてメイン処理に処理が戻ることになります。この間、メイン処理は待ち状態となります。putData()に関しても同様です。
このように、呼び出した先のメソッドの処理終了がすなわち元の処理の再開を意味する処理の流れを、同期処理といいます。戻りと再開のタイミングが同期していることを意味します。そして、Javaは、様々なメソッドを呼び出したとしても、それらが同一スレッド上で動作されることから、同期処理を基本とします。
非同期処理の必要性
ここで、calcData()に注目します。このcalcData()が時間のかかる処理だとします。その場合、メイン処理はずっと待ったままということになります。そして、例えば、このメイン処理が画面表示処理だとすると、そのアプリケーションを利用しているユーザからは処理がフリーズしたように思えます。これは、当然ですが、好ましい状況とは言えません。
この状況を避けるためには、calcData()の処理終了を待たない状況、calcData()の処理終了とメイン処理の処理再開が同期しないようにcalcData()を呼び出す必要があります。これが、非同期処理であり、時間のかかる処理、何かエラーの可能性が多々ある処理を呼び出す場合は、非同期処理で行うのを基本とします(図2)。
そして、Javaで非同期処理を実現するためには、それらの処理を別スレッドで行う必要があります。
[Note]UIスレッドとワーカースレッド
Androidでは、メイン処理となるのは、いうまでもなく画面表示処理です。この画面表示処理を行うスレッドを、Androidでは「UIスレッド」とよんでいます。一方、非同期で行う別スレッドのことを「ワーカースレッド」とよんでいます。