[dev_arch_opt_3.0][leakfix]修正由于匿名Runnable对象引用外部类引用造成的内存泄漏
This commit is contained in:
94
app/src/main/java/com/mogo/launcher/lancet/MemoryLeakFix.kt
Normal file
94
app/src/main/java/com/mogo/launcher/lancet/MemoryLeakFix.kt
Normal file
@@ -0,0 +1,94 @@
|
||||
package com.mogo.launcher.lancet
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.annotation.*
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.fragment.app.*
|
||||
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 java.lang.ref.*
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@Keep
|
||||
@Weaver
|
||||
@Group("memory_leak")
|
||||
class MemoryLeakFix {
|
||||
|
||||
@Insert
|
||||
@ImplementedInterface("java.lang.Runnable")
|
||||
@TargetMethod(methodName = "run")
|
||||
fun runProxy() {
|
||||
if (AccessSyntheticUtils.isTargetAlive(This.get())) {
|
||||
Origin.callVoid()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class AccessSyntheticUtils {
|
||||
|
||||
companion object {
|
||||
|
||||
private val fields = ConcurrentHashMap<String, WeakReference<Any>>()
|
||||
|
||||
@JvmStatic
|
||||
fun isTargetAlive(obj: Any): Boolean {
|
||||
try {
|
||||
val clazz = obj.javaClass
|
||||
if (!clazz.isAnonymousClass) {
|
||||
return true
|
||||
}
|
||||
val key = clazz.name
|
||||
return (fields[key] ?: clazz.declaredFields.find {
|
||||
it.isSynthetic &&
|
||||
((it.modifiers and Modifier.STATIC) == 0) &&
|
||||
(View::class.java.isAssignableFrom(it.type) or
|
||||
Context::class.java.isAssignableFrom(it.type) or
|
||||
Fragment::class.java.isAssignableFrom(it.type) or
|
||||
android.app.Fragment::class.java.isAssignableFrom(it.type) or
|
||||
Dialog::class.java.isAssignableFrom(it.type)
|
||||
)
|
||||
}?.let {
|
||||
it.isAccessible = true
|
||||
val wf = WeakReference(it.get(obj), ReferenceQueue())
|
||||
fields[key] = wf
|
||||
wf
|
||||
})?.also {
|
||||
if (it.isEnqueued) {
|
||||
//对像被垃圾回收了
|
||||
fields.remove(key)
|
||||
}
|
||||
}?.get()?.let { t ->
|
||||
when(t) {
|
||||
is View -> {
|
||||
ViewCompat.isAttachedToWindow(t)
|
||||
}
|
||||
is Activity -> {
|
||||
!t.isFinishing && !t.isDestroyed
|
||||
}
|
||||
is Fragment -> {
|
||||
!t.isDetached
|
||||
}
|
||||
is android.app.Fragment -> {
|
||||
!t.isDetached
|
||||
}
|
||||
is Dialog -> {
|
||||
t.window?.decorView?.let { v -> ViewCompat.isAttachedToWindow(v) } ?: false
|
||||
}
|
||||
else -> {
|
||||
true
|
||||
}
|
||||
}
|
||||
} ?: true
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user