WeakReference не работает в Котлине

105
13

Я реализую AsyncTask в Kotlin, и мне нужен WeakReference для обратного вызова, который выполняется в методе onPostExecute(). Я устанавливаю ссылку слушателя перед вызовом execute(), но после вызова onPostExecute() значение WeakReference равно null.


class PhotoRotationTask(uri: Uri, filePath: String, resolver: ContentResolver) : AsyncTask<Int, Int, Int>() {
private var weakRef : WeakReference<OnBitmapProcessedListener>? = null

var sourceUri : Uri
var resolver : ContentResolver
var destPath: String

init {
this.sourceUri = uri
this.resolver = resolver
this.destPath = filePath
}

fun setOnBitmapProcessedListener(listener: OnBitmapProcessedListener){
weakRef = WeakReference(listener)
Log.d("RotationTask", "set listener ${weakRef?.get() != null}") //This Log proves that weakRef is initialized before onPostExecute()
}

override fun doInBackground(vararg params: Int?): Int? {
//Bitmap processing, weakRef is never called in this function
}

override fun onPostExecute(result: Int?) {
Log.d("RotationTask", "result: $result") //This log proves that onPostExecute() is called eventually
weakRef!!.get()?.onBitmapProcessed() //This implies that weakRef is not null, because app never crashes, but onBitmapProcessed is not called, so the reference is gone.
}

}


Переменная listener изменяет интерфейс моей активности, поэтому она содержит ссылку на мою активность. Активность никогда не воссоздается, мой телефон по-прежнему, никогда не поворачивается или не трогается после запуска AsyncTask. Как очищается WeakReference?

спросил(а) 2016-05-05T02:34:00+03:00 4 года, 3 месяца назад
1
Решение
95

Проблема заключается в WeakReference и локальной переменной, которую вы передаете как listener.


WeakReference известно, что этот объект не содержит сбор мусора, поэтому, если нет другой доступной ссылки на него, он может быть переработан в любой момент как только метод ссылается на него через локальную переменную. И это именно то, что происходит в вашем случае, так как слабая ссылка становится null.


Решение состоит в том, чтобы хранить сильную ссылку на объект, который передается как listener где-то в вызывающем коде (так как он использует действие, сама деятельность может хранить его в свойстве, так что время жизни listener будет соответствовать активности).


Например, объявите свойство

lateinit var currentListener: OnBitmapProcessedListener

в коде действия, затем сохраните listener, созданный в этом свойстве:


val task = PhotoRotationTask(uri, filePath, resolver)

task.setOnBitmapProcessedListener(object : OnBitmapProcessedListener {
// here goes the implementation
}.apply { currentListener = this } // note this line
)


Если возможны несколько задач и слушателей, позаботьтесь о сохранении всех слушателей.

ответил(а) 2016-05-05T14:35:00+03:00 4 года, 3 месяца назад
39

Вам нужно провести сильную ссылку на OnBitmapProcessedListener где-то в другом месте, чтобы гарантировать, что GC не очистит WeakReference.

ответил(а) 2016-05-05T14:35:00+03:00 4 года, 3 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема