Scala で Android アプリ開発(AsyncTask 編)
ScalaでAndroidアプリ作成時、AsyncTaskの可変長引数メソッドが使えないことへの対策とサンプル ― Gist を丸パクリ。
Scala は、可変長引数を持つメソッドを上書きできないので、可変長引数を上書き済みの /path/to/hello-world/src/main/java/com/github/cooldaemon/HelloWorld/AsyncTask.java を作成する。
package com.github.cooldaemon.HelloWorld; public abstract class AsyncTask<Params, Progress, Result> extends android.os.AsyncTask<Params, Progress, Result> { @Override protected Result doInBackground(Params... params) { return doInBackground(params.length > 0 ? params[0] : null); } abstract protected Result doInBackground(Params param); @Override protected void onProgressUpdate(Progress... values) { onProgressUpdate(values.length > 0 ? values[0] : null); } protected void onProgressUpdate(Progress value) {} @SuppressWarnings({"unchecked"}) protected final void publishProgress(Progress value) { super.publishProgress(value); } }
用意した AsyncTask を継承して、別スレッドで処理したいタスクを記述する。
//可変長引数を使えない分は、case class で対応する case class FooParam(foo: String, bar: String) // AsyncTask から Activity を操作する(doInBackground は除く)ために Activity のインスタンスを渡しておく class FooTask(val activity: FooActivity) extends AsyncTask[FooParam, Int, Either[Throwable, Unit]] { override protected def onPreExecute() { // Activity に変化を加える。例えばダイアログの表示など } // doInBackground だけ別スレッドで動作する // doInBackground 内で publishProgress を使うと UI のスレッドに Int の値を送れる // 送った Int の値は onProgressUpdate で受け取れる override protected def doInBackground(param: FooParam): Either[Throwable, Unit] = { for { _ <- ham(param).right chick <- egg(param).right _ <- spam(param, chick).right } yield () } override protected def onProgressUpdate(progress: Int) { // プログレスの更新 } // AsyncTask の cancel メソッドを使用されると onCancelled が呼ばれる override protected def onCancelled() { // doInBackground の停止を促す。例えば doInBackground で参照しているフラグを onCancelled で更新するなど } override protected def onPostExecute(result: Either[HttpClientErrorResult, Unit]) { // Activity に変化を加える。例えばダイアログを消すなど } }
このコードは、画面の回転に対応していない。
画面が回転すると Activity のインスタンスは置き換えられるが AsyncTask は残り続けるので AsyncTask が保持する Activity のインスタンスを置き換える必要がある。
また、画面の回転と ProgressDialog を組み合わせる場合、画面回転後に ProgressDialog を再表示する必要があり、onCreateDialog に頼る事になる。
ProgressDialog を再表示する場合、以前の ProgressDialog 進行状況を引き継いだり、キャンセル処理を正常に動作させる必要があるので、なるべく画面が回転しないように固定しておいた方が良い。
もし、どうしても AsyncTask + ProgressDialog + 画面回転に対応したいのであれば、Activity から操作できる AsyncTask と ProgressDialog を管理する object を用意する。
この辺りは、ダウンローダ編で詳しく解説する。