diff --git a/app/src/main/java/com/mogo/launcher/lancet/MemoryLeakFix.kt b/app/src/main/java/com/mogo/launcher/lancet/MemoryLeakFix.kt index 4b9374ed5f..5357e485f6 100644 --- a/app/src/main/java/com/mogo/launcher/lancet/MemoryLeakFix.kt +++ b/app/src/main/java/com/mogo/launcher/lancet/MemoryLeakFix.kt @@ -7,10 +7,14 @@ import android.view.View import androidx.annotation.* import androidx.core.view.ViewCompat import androidx.fragment.app.* +import androidx.lifecycle.* +import androidx.lifecycle.Lifecycle.Event +import androidx.lifecycle.Lifecycle.Event.ON_DESTROY import com.knightboost.lancet.api.* import com.knightboost.lancet.api.annotations.* import com.knightboost.lancet.api.annotations.Weaver import com.mogo.eagle.core.utilcode.kotlin.* +import io.netty.util.internal.ConcurrentSet import java.lang.ref.* import java.lang.reflect.Modifier import java.util.concurrent.ConcurrentHashMap @@ -35,6 +39,7 @@ internal class AccessSyntheticUtils { companion object { private val fields = ConcurrentHashMap>() + private val observers = ConcurrentSet() @JvmStatic fun isTargetAlive(obj: Any): Boolean { @@ -64,31 +69,72 @@ internal class AccessSyntheticUtils { fields.remove(key) } }?.get()?.let { t -> - when(t) { + var lifecycle: Lifecycle? = null + val ret = when (t) { is View -> { + lifecycle = t.lifecycleOwner.lifecycle ViewCompat.isAttachedToWindow(t) } is Activity -> { + lifecycle = t.findViewById(android.R.id.content)?.lifecycleOwner?.lifecycle !t.isFinishing && !t.isDestroyed } is Fragment -> { + lifecycle = t.lifecycle !t.isDetached } is android.app.Fragment -> { + lifecycle = t.view?.lifecycleOwner?.lifecycle !t.isDetached } is Dialog -> { - t.window?.decorView?.let { v -> ViewCompat.isAttachedToWindow(v) } ?: false + t.window?.decorView?.let { + v -> + lifecycle = v.lifecycleOwner.lifecycle + ViewCompat.isAttachedToWindow(v) + } ?: false } else -> { true } } + if (!ret) { + assignFinalFieldNull(obj, t.javaClass) + } else { + val l = lifecycle + if (l != null && !observers.contains(key)) { + observers.add(key) + l.addObserver(object : LifecycleEventObserver { + override fun onStateChanged(source: LifecycleOwner, event: Event) { + if (event == ON_DESTROY) { + assignFinalFieldNull(obj, t.javaClass) + observers.remove(key) + } + } + }) + } + } + ret } ?: true } catch (t: Throwable) { t.printStackTrace() } return true } + + @JvmStatic + private fun assignFinalFieldNull(obj: Any, fieldType: Class<*>) { + try { + obj.javaClass.declaredFields.find { + it.isSynthetic && + ((it.modifiers and Modifier.STATIC) == 0) && it.type == fieldType + }?.also { + it.isAccessible = true + it.set(obj, null) + } + } catch (t: Throwable) { + t.printStackTrace() + } + } } } \ No newline at end of file