Android が InputMethodManager のメモリ リーク問題を解決

Android 11のInputMethodManagerのソースコードで、次のようにwindowDismissed()を確認します。

/**
 * An empty method only to avoid crashes of apps that call this method via reflection and do not
 * handle {@link NoSuchMethodException} in a graceful manner.
 *
 * @deprecated This is an empty method.  No framework method must call this method.
 * @hide
 */
public void windowDismissed(IBinder appWindowToken) {
    
    
    // Intentionally empty.
    //
    // It seems that some applications call this method via reflection to null clear the
    // following fields that used to exist in InputMethodManager:
    //  * InputMethodManager#mCurRootView
    //  * InputMethodManager#mServedView
    //  * InputMethodManager#mNextServedView
    // so that these objects can be garbage-collected when an Activity gets dismissed.
    //
    // It is indeed true that older versions of InputMethodManager had issues that prevented
    // these fields from being null-cleared when it should have been, but the understanding of
    // the engineering team is that all known issues have already been fixed as of Android 10.
    //
    // For older devices, developers can work around the object leaks by using
    // androidx.activity.ComponentActivity.
    // See https://issuetracker.google.com/u/1/issues/37122102 for details.
    //
    // If you believe InputMethodManager is leaking objects in API 24 or any later version,
    // please file a bug at https://issuetracker.google.com/issues/new?component=192705.
}

/*
* 以下の 3 つのフィールドは Android 10 より前のバージョンに存在し、以降は変更されています。
* Android 10 より前のバージョンでは、アクティビティが閉じられたときに、リフレクションを通じてアクティビティを null に設定できるため、メモリ リークを防ぐためにアクティビティ内のビューへの参照が保持されなくなります。
*InputMethodManager#mCurRootView
*InputMethodManager#mServedView
*InputMethodManager#mNextServedView
*
* Android 10 以降ではすべての既知の問題が修正されました。
※ 古いバージョンの場合は、androidx.activity.ComponentActivity とそのサブクラスを使用することをお勧めします。
* issues/37122102、Android N/7.0 (API 24) について説明し、修復を開始しました。
*
* Android 11 ソース コード: http://aospxref.com/android-11.0.0_r21/xref/frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java
* Android 10 ソース コード: http:// aospxref.com/android-10.0.0_r47/xref/frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java
*/

解決策: android10 未満およびComponentActivity以外の、 InputMethodManagerobject 内のmCurRootViewmServedView、の 3 つの属性を反射的に取得mNextServedViewし、それらを View 型に変換し、ビューのコンテキストがコンテキストと等しいと判断した場合、この属性を null に設定します。リリースされるアクティビティの。

fun fixMemoryLeak(context: Context?) {
    
    
    try {
    
    
        context ?: return
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) return // android 10 已修复
        if (context is ComponentActivity) return // androidx.activity.ComponentActivity 已修复
        val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager ?: return
        imm.javaClass.declaredFields.filter {
    
    
            it.name == "mCurRootView" || it.name == "mServedView" || it.name == "mNextServedView"
        }.forEach {
    
     filed ->
            val origin = filed.isAccessible
            if (!origin) {
    
    
                filed.isAccessible = true
            }
            (filed.get(imm) as? View)?.takeIf {
    
     it.context == context }?.also {
    
    
                filed.set(imm, null)
            }
            filed.isAccessible = origin
        }
    } catch (e: Exception) {
    
    
        e.printStackTrace()
    }
}

おすすめ

転載: blog.csdn.net/jjwwmlp456/article/details/124580048
おすすめ