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)
}
}