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