prevent MainActivity from leaking through the DrawerImageLoader singleton (#4153)

Another fix for a memory leak. This one is not as big as #4150, but
still worth fixing for memory constrained devices imo.
The `DrawerImageLoader` implementation (a global singleton) references a
member of the `MainActivity`, causing the whole activity to leak.

This weird construct was introduced in #1989 to fix a crash, but I think
since we migrated to coroutines it is no longer necessary because all
calls get correctly cancelled. I tried reproducing the crash but could
not, so I'm pretty sure it is fine. I would appreciate it if someone
else could try it as well though.

(The crash could be reproduced on slow internet, when
`onFetchUserInfoSuccess` was called while the activity was being
destroyed, causing Glide to crash the app because it can't use destroyed
activities. `onFetchUserInfoSuccess` is now no longer called in this
case because it is inside a `lifecycleScope.launch` block.)
This commit is contained in:
Konrad Pozniak 2023-12-10 09:44:53 +01:00 committed by GitHub
parent ee3760fcc9
commit 75c42cb5c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 15 additions and 12 deletions

View File

@ -56,7 +56,6 @@ import androidx.preference.PreferenceManager
import androidx.viewpager2.widget.MarginPageTransformer import androidx.viewpager2.widget.MarginPageTransformer
import at.connyduck.calladapter.networkresult.fold import at.connyduck.calladapter.networkresult.fold
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.RequestManager
import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.FixedSizeDrawable import com.bumptech.glide.request.target.FixedSizeDrawable
@ -174,8 +173,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
private val preferences by unsafeLazy { PreferenceManager.getDefaultSharedPreferences(this) } private val preferences by unsafeLazy { PreferenceManager.getDefaultSharedPreferences(this) }
private lateinit var glide: RequestManager
// We need to know if the emoji pack has been changed // We need to know if the emoji pack has been changed
private var selectedEmojiPack: String? = null private var selectedEmojiPack: String? = null
@ -187,7 +184,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
private var directMessageTab: TabLayout.Tab? = null private var directMessageTab: TabLayout.Tab? = null
@Suppress("DEPRECATION")
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -266,8 +262,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
window.statusBarColor = Color.TRANSPARENT // don't draw a status bar, the DrawerLayout and the MaterialDrawerLayout have their own window.statusBarColor = Color.TRANSPARENT // don't draw a status bar, the DrawerLayout and the MaterialDrawerLayout have their own
setContentView(binding.root) setContentView(binding.root)
glide = Glide.with(this)
binding.composeButton.setOnClickListener { binding.composeButton.setOnClickListener {
val composeIntent = Intent(applicationContext, ComposeActivity::class.java) val composeIntent = Intent(applicationContext, ComposeActivity::class.java)
startActivity(composeIntent) startActivity(composeIntent)
@ -562,11 +556,13 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
DrawerImageLoader.init(object : AbstractDrawerImageLoader() { DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) { override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
if (animateAvatars) { if (animateAvatars) {
glide.load(uri) Glide.with(imageView)
.load(uri)
.placeholder(placeholder) .placeholder(placeholder)
.into(imageView) .into(imageView)
} else { } else {
glide.asBitmap() Glide.with(imageView)
.asBitmap()
.load(uri) .load(uri)
.placeholder(placeholder) .placeholder(placeholder)
.into(imageView) .into(imageView)
@ -574,7 +570,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
} }
override fun cancel(imageView: ImageView) { override fun cancel(imageView: ImageView) {
glide.clear(imageView) Glide.with(imageView).clear(imageView)
} }
override fun placeholder(ctx: Context, tag: String?): Drawable { override fun placeholder(ctx: Context, tag: String?): Drawable {
@ -979,7 +975,8 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
} }
private fun onFetchUserInfoSuccess(me: Account) { private fun onFetchUserInfoSuccess(me: Account) {
glide.asBitmap() Glide.with(header.accountHeaderBackground)
.asBitmap()
.load(me.header) .load(me.header)
.into(header.accountHeaderBackground) .into(header.accountHeaderBackground)
@ -1021,7 +1018,10 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
val navIconSize = resources.getDimensionPixelSize(R.dimen.avatar_toolbar_nav_icon_size) val navIconSize = resources.getDimensionPixelSize(R.dimen.avatar_toolbar_nav_icon_size)
if (animateAvatars) { if (animateAvatars) {
glide.asDrawable().load(avatarUrl).transform(RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp))) Glide.with(this)
.asDrawable()
.load(avatarUrl)
.transform(RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp)))
.apply { .apply {
if (showPlaceholder) placeholder(R.drawable.avatar_default) if (showPlaceholder) placeholder(R.drawable.avatar_default)
} }
@ -1048,7 +1048,10 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
} }
}) })
} else { } else {
glide.asBitmap().load(avatarUrl).transform(RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp))) Glide.with(this)
.asBitmap()
.load(avatarUrl)
.transform(RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_36dp)))
.apply { .apply {
if (showPlaceholder) placeholder(R.drawable.avatar_default) if (showPlaceholder) placeholder(R.drawable.avatar_default)
} }