@[Toc](Leak in FragmentContainerView/ViewGroup.mCurrentDragChild using Drag 拖动手势)
记录一次我在Fragment中使用startDrag, 造成FragmentContainerView泄漏的解决方案
1.问题
- 如图, 一次偶然的机会, 我在使用Jetpack的navigator的时候, 使用拖动startDrag在子Fragment中通过LeakCanary发现了严重的内存泄漏
- 发现此类问题并不多, 只有github的1963汇报了此问题, 并且没有实际的解决方式
- 锅又到google那边了😂,无妨, 点开看看, 留下了到此一游....那么就自己解决吧
2.解决方案
通过反射强制使其置null, 释放, 如下代码
object UtilKDragAndDrop {
private const val TAG = "UtilKDragAndDrop>>>>>"
@JvmStatic
@Throws(Exception::class)
fun fixDragAndDropLeak(vararg views: View) {
var tempView: View
views.forEach { v ->
tempView = v
while (tempView.parent != null && tempView.parent is ViewGroup) {
tempView = tempView.parent as ViewGroup
fixDragAndDropLeak(tempView)
}
}
}
@JvmStatic
@Throws(Exception::class)
fun fixDragAndDropLeak(view: View) {
val field: Field
val fieldObj: Any?
try {
field = UtilKReflect.getField(view, "mCurrentDragChild")
if (!field.isAccessible) field.isAccessible = true
fieldObj = field.get(view)
if (fieldObj != null) {
field.set(view, null)
Log.d(TAG, "fixDragAndDropLeak: set viewGroup ${view.javaClass.simpleName} mCurrentDragChild null")
}
} catch (e: Exception) {
e.printStackTrace()
e.message?.et(TAG)
}
}
}
- 关于UtilKReflect可见【Java】UtilKReflect Java反射工具类
- 再加上Lifecycle使用, 使其在onPause之前释放
override fun onPause(owner: LifecycleOwner) {
try {
_viewList.forEach {
UtilKDragAndDrop.fixDragAndDropLeak(it.first, it.second)
}
_viewList.clear()
} catch (e: Exception) {
e.printStackTrace()
e.message?.et(TAG)
}
super.onPause(owner)
}