英文:
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
专注分享java语言的经验与见解,让所有开发者获益!

评论