无法阻止AppOpsManager泄漏内存

huangapple 未分类评论46阅读模式
英文:

Cannot stop AppOpsManager from leaking memory

问题

LeakCanary报告了AppOpsManager在我认为不应该发生内存泄漏的情况下泄漏了内存(基于OnOpChangedListener不再触发)。我是否做错了什么?

请求权限:

    AppOpsManager.OnOpChangedListener onOpChangedListener = null;
    AppOpsManager appOpsManager = null;

    public void requestUsagePermissionAndWait() {

        appOpsManager = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
        onOpChangedListener = new AppOpsManager.OnOpChangedListener() {
            @Override
            public void onOpChanged(String op, String packageName) {
                if (appOpsManager != null) {
                    appOpsManager.stopWatchingMode(this);

                    if (onOpChangedListener != null) {
                        appOpsManager.stopWatchingMode(onOpChangedListener);
                        onOpChangedListener = null;
                    }
                    appOpsManager = null;
                }
                ((Activity) getContext()).runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        onPermissionGranted();
                    }
                });

            }
        };
        appOpsManager.startWatchingMode(AppOpsManager.OPSTR_GET_USAGE_STATS, getContext().getPackageName(), onOpChangedListener);
    }

LeakCanary日志:


 D/LeakCanary: ┬
 D/LeakCanary: ├─ android.app.AppOpsManager$1
 D/LeakCanary: │    Leaking: UNKNOWN
 D/LeakCanary: │    Anonymous subclass of com.android.internal.app.IAppOpsCallback$Stub
 D/LeakCanary: │    GC Root: Global variable in native code
 D/LeakCanary: │    ↓ AppOpsManager$1.val$callback
 D/LeakCanary: │                      ~~~~~~~~~~~~
 D/LeakCanary: ├─ com.abc.zxy.views.MyCustomView$9
 D/LeakCanary: │    Leaking: UNKNOWN
 D/LeakCanary: │    Anonymous class implementing android.app.AppOpsManager$OnOpChangedListener
 D/LeakCanary: │    ↓ MyCustomView$9.this$0
 D/LeakCanary: │                               ~~~~~~
 D/LeakCanary: ├─ com.abc.zxy.views.MyCustomView
 D/LeakCanary: │    Leaking: YES (View.mContext引用了一个已销毁的activity)
 D/LeakCanary: │    mContext实例为com.abc.zxy.activities.ActivityMain,mDestroyed = true
 D/LeakCanary: │    View#mParent已设置
 D/LeakCanary: │    View#mAttachInfo为null(视图已分离)
 D/LeakCanary: │    View.mWindowAttachCount = 1
 D/LeakCanary: │    ↓ MyCustomView.mParent
 D/LeakCanary: ├─ android.widget.LinearLayout
 D/LeakCanary: │    Leaking: YES (MyCustomView↑泄漏了,View.mContext引用了一个已销毁的activity)
 D/LeakCanary: │    mContext实例为com.abc.zxy.activities.ActivityMain,mDestroyed = true
 D/LeakCanary: │    View#mParent已设置
 D/LeakCanary: │    View#mAttachInfo为null(视图已分离)
 D/LeakCanary: │    View.mWindowAttachCount = 1
 D/LeakCanary: │    ↓ LinearLayout.mParent
 D/LeakCanary: ├─ android.widget.LinearLayout
 D/LeakCanary: │    Leaking: YES (LinearLayout↑泄漏了,View.mContext引用了一个已销毁的activity)
 D/LeakCanary: │    mContext实例为com.abc.zxy.activities.ActivityMain,mDestroyed = true
 D/LeakCanary: │    View#mParent已设置
 D/LeakCanary: │    View#mAttachInfo为null(视图已分离)
 D/LeakCanary: │    View.mWindowAttachCount = 1
 D/LeakCanary: │    ↓ LinearLayout.mParent
 D/LeakCanary: ├─ android.widget.ScrollView
 D/LeakCanary: │    Leaking: YES (LinearLayout↑泄漏了,View.mContext引用了一个已销毁的activity)
 D/LeakCanary: │    mContext实例为com.abc.zxy.activities.ActivityMain,mDestroyed = true
 D/LeakCanary: │    View#mParent已设置
 D/LeakCanary: │    View#mAttachInfo为null(视图已分离)
 D/LeakCanary: │    View.mWindowAttachCount = 1
 D/LeakCanary: │    ↓ ScrollView.mParent
 D/LeakCanary: ╰→ android.support.constraint.ConstraintLayout
 D/LeakCanary: ​     Leaking: YES (ScrollView↑泄漏了,View.mContext引用了一个已销毁的activity,ObjectWatcher曾监视此对象)
 D/LeakCanary: ​     mContext实例为com.abc.zxy.activities.ActivityMain,mDestroyed = true
 D/LeakCanary: ​     View#mParent为null
 D/LeakCanary: ​     View#mAttachInfo为null(视图已分离)
 D/LeakCanary: ​     View.mWindowAttachCount = 1
 D/LeakCanary: ​     key = 1dcc6d06-d2f2-4e0a-a6d8-ea6ae6688596
 D/LeakCanary: ​     watchDurationMillis = 5488
 D/LeakCanary: ​     retainedDurationMillis = 487
英文:

LeakCanary reports AppOpsManager leaking memory when I think it shouldn't happen (based on
OnOpChangedListener not firing anymore). Am I doing something wrong?

Requesting permissions:

    AppOpsManager.OnOpChangedListener onOpChangedListener = null;
    AppOpsManager appOpsManager = null;

    public void requestUsagePermissionAndWait() {

        appOpsManager = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
        onOpChangedListener = new AppOpsManager.OnOpChangedListener() {
            @Override
            public void onOpChanged(String op, String packageName) {
                if (appOpsManager != null) {
                    appOpsManager.stopWatchingMode(this);

                    if (onOpChangedListener != null) {
                        appOpsManager.stopWatchingMode(onOpChangedListener);
                        onOpChangedListener = null;
                    }
                    appOpsManager = null;
                }
                ((Activity) getContext()).runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        onPermissionGranted();
                    }
                });

            }
        };
        appOpsManager.startWatchingMode(AppOpsManager.OPSTR_GET_USAGE_STATS, getContext().getPackageName(), onOpChangedListener);
    }

LeakCanary log:


 D/LeakCanary: ┬
 D/LeakCanary: ├─ android.app.AppOpsManager$1
 D/LeakCanary: │    Leaking: UNKNOWN
 D/LeakCanary: │    Anonymous subclass of com.android.internal.app.IAppOpsCallback$Stub
 D/LeakCanary: │    GC Root: Global variable in native code
 D/LeakCanary: │    ↓ AppOpsManager$1.val$callback
 D/LeakCanary: │                      ~~~~~~~~~~~~
 D/LeakCanary: ├─ com.abc.zxy.views.MyCustomView$9
 D/LeakCanary: │    Leaking: UNKNOWN
 D/LeakCanary: │    Anonymous class implementing android.app.AppOpsManager$OnOpChangedListener
 D/LeakCanary: │    ↓ MyCustomView$9.this$0
 D/LeakCanary: │                               ~~~~~~
 D/LeakCanary: ├─ com.abc.zxy.views.MyCustomView
 D/LeakCanary: │    Leaking: YES (View.mContext references a destroyed activity)
 D/LeakCanary: │    mContext instance of com.abc.zxy.activities.ActivityMain with mDestroyed = true
 D/LeakCanary: │    View#mParent is set
 D/LeakCanary: │    View#mAttachInfo is null (view detached)
 D/LeakCanary: │    View.mWindowAttachCount = 1
 D/LeakCanary: │    ↓ MyCustomView.mParent
 D/LeakCanary: ├─ android.widget.LinearLayout
 D/LeakCanary: │    Leaking: YES (MyCustomView↑ is leaking and View.mContext references a destroyed activity)
 D/LeakCanary: │    mContext instance of com.abc.zxy.activities.ActivityMain with mDestroyed = true
 D/LeakCanary: │    View#mParent is set
 D/LeakCanary: │    View#mAttachInfo is null (view detached)
 D/LeakCanary: │    View.mWindowAttachCount = 1
 D/LeakCanary: │    ↓ LinearLayout.mParent
 D/LeakCanary: ├─ android.widget.LinearLayout
 D/LeakCanary: │    Leaking: YES (LinearLayout↑ is leaking and View.mContext references a destroyed activity)
 D/LeakCanary: │    mContext instance of com.abc.zxy.activities.ActivityMain with mDestroyed = true
 D/LeakCanary: │    View#mParent is set
 D/LeakCanary: │    View#mAttachInfo is null (view detached)
 D/LeakCanary: │    View.mWindowAttachCount = 1
 D/LeakCanary: │    ↓ LinearLayout.mParent
 D/LeakCanary: ├─ android.widget.ScrollView
 D/LeakCanary: │    Leaking: YES (LinearLayout↑ is leaking and View.mContext references a destroyed activity)
 D/LeakCanary: │    mContext instance of com.abc.zxy.activities.ActivityMain with mDestroyed = true
 D/LeakCanary: │    View#mParent is set
 D/LeakCanary: │    View#mAttachInfo is null (view detached)
 D/LeakCanary: │    View.mWindowAttachCount = 1
 D/LeakCanary: │    ↓ ScrollView.mParent
 D/LeakCanary: ╰→ android.support.constraint.ConstraintLayout
 D/LeakCanary: ​     Leaking: YES (ScrollView↑ is leaking and View.mContext references a destroyed activity and ObjectWatcher was watching this)
 D/LeakCanary: ​     mContext instance of com.abc.zxy.activities.ActivityMain with mDestroyed = true
 D/LeakCanary: ​     View#mParent is null
 D/LeakCanary: ​     View#mAttachInfo is null (view detached)
 D/LeakCanary: ​     View.mWindowAttachCount = 1
 D/LeakCanary: ​     key = 1dcc6d06-d2f2-4e0a-a6d8-ea6ae6688596
 D/LeakCanary: ​     watchDurationMillis = 5488
 D/LeakCanary: ​     retainedDurationMillis = 487

huangapple
  • 本文由 发表于 2020年4月7日 02:23:29
  • 转载请务必保留本文链接:https://java.coder-hub.com/61066419.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定