Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как используется WeakReference
WeakReference — это специальный вид ссылки в Java, который позволяет сборщику мусора (GC) удалить объект, даже если на него есть ссылка. В отличие от обычных (сильных) ссылок, WeakReference не препятствует garbage collection. Это особенно полезно в Android для предотвращения утечек памяти.
Основной концепт
// Обычная (strong) ссылка — объект НЕ может быть собран GC
val user: User = User("Alice")
// WeakReference — объект МОЖЕТ быть собран GC
val userRef: WeakReference<User> = WeakReference(user)
// Получить объект
val userOrNull = userRef.get() // может быть null!
if (userOrNull != null) {
println(userOrNull.name)
}
Когда WeakReference становится null
WeakReference обнуляется в следующих сценариях:
- Нет больше strong ссылок — если единственная strong ссылка удалена
- Произошла сборка мусора — после GC объект с WeakReference может быть удалён
- Нет более срочных ссылок — если есть PhantomReference, он имеет приоритет
class Cache {
private val weakCache = WeakHashMap<String, User>()
fun putUser(key: String, user: User) {
weakCache[key] = user
}
fun getUser(key: String): User? {
return weakCache[key] // может вернуть null после GC
}
}
Практический пример: предотвращение утечки памяти
Проблема: Если передать Context в AsyncTask или Handler, может быть утечка памяти:
// ПЛОХО — утечка памяти!
class LoadUserTask(private val activity: MainActivity) : AsyncTask<String, Void, User>() {
override fun doInBackground(vararg params: String?): User {
// долгая операция
Thread.sleep(5000)
return fetchUserFromServer(params[0])
}
override fun onPostExecute(result: User) {
// Activity может быть удалена из памяти, но AsyncTask всё ещё держит ссылку!
activity.updateUI(result)
}
}
Если пользователь закроет Activity во время выполнения AsyncTask, Activity остаётся в памяти.
Решение с WeakReference:
// ХОРОШО — используем WeakReference
class LoadUserTask(activity: MainActivity) : AsyncTask<String, Void, User>() {
private val activityRef = WeakReference(activity)
override fun doInBackground(vararg params: String?): User {
Thread.sleep(5000)
return fetchUserFromServer(params[0])
}
override fun onPostExecute(result: User) {
val activity = activityRef.get()
if (activity != null && !activity.isFinishing) {
activity.updateUI(result)
}
// Если Activity был удалён GC, просто ничего не делаем
}
}
WeakReference vs другие типы ссылок
// StrongReference (обычная переменная)
val user = User("Bob") // Объект НЕ может быть удалён
// WeakReference
val userWeak = WeakReference(User("Bob")) // Объект МОЖЕТ быть удалён при GC
// SoftReference
val userSoft = SoftReference(User("Bob")) // Удаляется при нехватке памяти
// PhantomReference
val userPhantom = PhantomReference(User("Bob"), queue) // Всегда удаляется, для очистки ресурсов
// Пример с иерархией
var user: User? = User("Charlie") // Strong reference
val weakRef = WeakReference(user)
val softRef = SoftReference(user)
user = null // Удаляем strong reference
// Теперь объект может быть собран GC
// weakRef.get() может вернуть null
// softRef.get() вернёт null при нехватке памяти
WeakHashMap в Android
WeakHashMap очень полезен для кэширования, когда ключи должны быть удаляемы:
class ImageCache {
// Изображения удаляются автоматически при GC
private val cache = WeakHashMap<String, Bitmap>()
fun put(key: String, bitmap: Bitmap) {
cache[key] = bitmap
}
fun get(key: String): Bitmap? {
return cache[key] // может быть null после GC
}
fun size(): Int {
return cache.size // size меняется после GC!
}
}
// Использование
val imageCache = ImageCache()
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.image)
imageCache.put("avatar", bitmap)
// Позже
val cachedBitmap = imageCache.get("avatar") // может быть null
Handler и Runnable с WeakReference
Проблема: Handler может содержать ссылку на Activity:
// ПЛОХО
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Handler(Looper.getMainLooper()).postDelayed({
// Если Activity удалена, это может вызвать crash
updateUI()
}, 5000)
}
}
// ХОРОШО — используем WeakReference
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val handler = WeakHandler(this)
handler.postDelayed({ updateUI() }, 5000)
}
}
class WeakHandler<T>(target: T) : Handler(Looper.getMainLooper()) {
private val targetRef = WeakReference(target)
fun postDelayed(action: () -> Unit, delayMillis: Long) {
postDelayed({
val target = targetRef.get()
if (target != null) {
action.invoke()
}
}, delayMillis)
}
}
Listener callbacks с WeakReference
class LocationManager {
private val listeners = mutableSetOf<WeakReference<LocationListener>>()
fun addListener(listener: LocationListener) {
listeners.add(WeakReference(listener))
}
fun removeListener(listener: LocationListener) {
listeners.removeAll { it.get() == null || it.get() == listener }
}
fun notifyListeners(location: Location) {
// Очищаем мёртвые ссылки
listeners.removeAll { it.get() == null }
// Уведомляем живых слушателей
for (ref in listeners) {
ref.get()?.onLocationChanged(location)
}
}
}
interface LocationListener {
fun onLocationChanged(location: Location)
}
Правила использования WeakReference
- Не используй для критичных данных — объект может быть удалён в любой момент
- Всегда проверяй null — перед использованием вызови get()
- Используй для кэшей — WeakHashMap идеален для кэширования
- Используй для обратных вызовов — Listener, Callback, Handler
- Не переусложняй — если не нужно, не используй
Когда НЕ использовать WeakReference
// ПЛОХО — критичные данные
val userRef = WeakReference(currentUser) // может быть null в любой момент
// ХОРОШО — используй strong reference
val user: User = currentUser
Производительность
- WeakReference немного медленнее обычных ссылок (нужно дополнительное отслеживание)
- В большинстве случаев разница незаметна
- Главный плюс — предотвращение утечек памяти
WeakReference — это мощный инструмент для работы с памятью в Android, но используй его осознанно и только там, где это действительно нужно.