Android
Kotlin

AsyncTaskに安全にcallbackを持たせたい

More than 1 year has passed since last update.

Android開発に関する初投稿です。

Android初心者なので、アドバイス・指摘大歓迎です。


背景

重い処理をUIスレッド外で行いたいときに使うAsyncTaskはコールバックで処理を受け取る形式になっていません。

しかし、迂闊にコールバックを受け取れるようにするとメモリリークの危険があります。


AsyncTaskで安全にcallbackを実行する方法

ActivityをweakReferenceで保持し、callBackをActivityに持たせてonPostExecute()内で実行します。

Activityが弱参照になっているので、Activityがdestroyされた時にActivityが適切にGCされます。

class AsyncTaskSample<T>(activity: T) : AsyncTask<String, Unit, String>() where T : AppCompatActivity, T : AsyncTaskSample.Listener {

val weakActivity = WeakReference(activity)
interface Listener {
fun onCompleteAsyncTask(result: Uri?): Unit
}

override fun doInBackground(vararg params: String?): String? {
return params[0]
}

override fun onPostExecute(result: String?) {
super.onPostExecute(result)
weakActivity?.onCompleteAsyncTask(result)
}
}


ダメな例: callBackをコンストラクタに渡す

doInBackgroundの最中にActivityがdestroyされてもGCが働かず、メモリー上にActivityが残り続けます。その為、最悪の場合メモリーリークを起こします。

class AsyncTaskSample(callback: (String?) -> Unit) : AsyncTask<String, Unit, String>() {

override fun doInBackground(vararg params: String?): String? {
}

override fun onPostExecute(result: String?) {
super.onPostExecute(result)
callback(result)
}
}


ダメな例: callBackをWeakReferenceで保持する

callBackに渡したラムダが予期せぬタイミングでGCされ、発火しなくなることがあります。

class AsyncTaskSample(callback: (String?) -> Unit) : AsyncTask<String, Unit, String>() {

val weakCallback = WeakReference(callback)
override fun doInBackground(vararg params: String?): String? {
return params[0]
}

override fun onPostExecute(result: String?) {
super.onPostExecute(result)
weakCallback.get()?.invoke(result)
}
}