是什么导致我的 AlertDialog 在 Firebase 回调方法中泄漏?
What is causing my AlertDialog to leak in Firebase callback method?
我有一个使用 AlertDialog Builder 创建的 AlertDialog:
private void setProgressDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.alertDialogTheme);
builder.setView(R.layout.alert_dialog_login_progress);
mAlertDialog = builder.create();
mAlertDialog.setCancelable(false);
mAlertDialog.setCanceledOnTouchOutside(false);
mAlertDialog.show();
}
我正在使用 FirebaseAuth 的登录方法:
private void signIn() {
mAuth.signInWithEmailAndPassword(mEmail, mPassword)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
mAlertDialog.dismiss();
Toast.makeText(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
}
});
}
我已经将代码减少到这个程度,但它仍然会泄漏。我不会改变活动。
泄漏是因为我输入了错误的密码,并调用了.isSuccessful()
方法。
我也在 UI 线程上尝试了 运行,但它仍然泄漏:
runOnUiThread(new Runnable() {
public void run() {
mAlertDialog.dismiss();
Toast.makeText(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
});
完整代码如下:
这是漏洞:
┬───
│ GC Root: Local variable in native code
│
├─ android.os.HandlerThread instance
│ Leaking: NO (PathClassLoader↓ is not leaking)
│ Thread name: 'GoogleApiHandler'
│ ↓ Thread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│ Leaking: NO (InternalLeakCanary↓ is not leaking and A ClassLoader is never
│ leaking)
│ ↓ ClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│ Leaking: NO (InternalLeakCanary↓ is not leaking)
│ ↓ Object[].[218]
├─ leakcanary.internal.InternalLeakCanary class
│ Leaking: NO (LoginActivity↓ is not leaking and a class is never leaking)
│ ↓ static InternalLeakCanary.resumedActivity
├─ instance
│ Leaking: NO (Activity#mDestroyed is false)
│ mApplication instance of android.app.Application
│ mBase instance of android.app.ContextImpl
│ ↓ LoginActivity.mAlertDialog
│ ~~~~~~~~~~~~
├─ androidx.appcompat.app.AlertDialog instance
│ Leaking: UNKNOWN
│ Retaining 157.5 kB in 2114 objects
│ mContext instance of android.view.ContextThemeWrapper, wrapping activity
│ with mDestroyed = false
│ Dialog#mDecor is null
│ ↓ Dialog.mWindow
│ ~~~~~~~
├─ com.android.internal.policy.PhoneWindow instance
│ Leaking: UNKNOWN
│ Retaining 15.3 kB in 300 objects
│ mContext instance of android.view.ContextThemeWrapper, wrapping activity
│ with mDestroyed = false
│ Window#mDestroyed is false
│ ↓ PhoneWindow.mDecor
│ ~~~~~~
╰→ com.android.internal.policy.DecorView instance
Leaking: YES (ObjectWatcher was watching this because com.android.
internal.policy.DecorView received View#onDetachedFromWindow() callback)
Retaining 4.7 kB in 42 objects
key = f381c0b5-587b-4d68-b453-be1c851ce257
watchDurationMillis = 31367
retainedDurationMillis = 26366
View not part of a window view hierarchy
View.mAttachInfo is null (view detached)
View.mWindowAttachCount = 1
mContext instance of android.view.ContextThemeWrapper, wrapping activity
with mDestroyed = false
为什么会漏水,我该如何解决?
在尝试找出问题几个小时后,当我在调用 mAlertDialog.dismiss();
后将 mAlertDialog
设置为 null
时,内存泄漏不再发生
mAlertDialog.dismiss();
mAlertDialog = null;
Toast.makeText(LoginActivity.this, "Authentication failed.",Toast.LENGTH_SHORT).show();
我不知道为什么会这样...但它阻止了泄漏的发生。
我有一个使用 AlertDialog Builder 创建的 AlertDialog:
private void setProgressDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.alertDialogTheme);
builder.setView(R.layout.alert_dialog_login_progress);
mAlertDialog = builder.create();
mAlertDialog.setCancelable(false);
mAlertDialog.setCanceledOnTouchOutside(false);
mAlertDialog.show();
}
我正在使用 FirebaseAuth 的登录方法:
private void signIn() {
mAuth.signInWithEmailAndPassword(mEmail, mPassword)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
mAlertDialog.dismiss();
Toast.makeText(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
}
});
}
我已经将代码减少到这个程度,但它仍然会泄漏。我不会改变活动。
泄漏是因为我输入了错误的密码,并调用了.isSuccessful()
方法。
我也在 UI 线程上尝试了 运行,但它仍然泄漏:
runOnUiThread(new Runnable() {
public void run() {
mAlertDialog.dismiss();
Toast.makeText(LoginActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
});
完整代码如下:
这是漏洞:
┬───
│ GC Root: Local variable in native code
│
├─ android.os.HandlerThread instance
│ Leaking: NO (PathClassLoader↓ is not leaking)
│ Thread name: 'GoogleApiHandler'
│ ↓ Thread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│ Leaking: NO (InternalLeakCanary↓ is not leaking and A ClassLoader is never
│ leaking)
│ ↓ ClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│ Leaking: NO (InternalLeakCanary↓ is not leaking)
│ ↓ Object[].[218]
├─ leakcanary.internal.InternalLeakCanary class
│ Leaking: NO (LoginActivity↓ is not leaking and a class is never leaking)
│ ↓ static InternalLeakCanary.resumedActivity
├─ instance
│ Leaking: NO (Activity#mDestroyed is false)
│ mApplication instance of android.app.Application
│ mBase instance of android.app.ContextImpl
│ ↓ LoginActivity.mAlertDialog
│ ~~~~~~~~~~~~
├─ androidx.appcompat.app.AlertDialog instance
│ Leaking: UNKNOWN
│ Retaining 157.5 kB in 2114 objects
│ mContext instance of android.view.ContextThemeWrapper, wrapping activity
│ with mDestroyed = false
│ Dialog#mDecor is null
│ ↓ Dialog.mWindow
│ ~~~~~~~
├─ com.android.internal.policy.PhoneWindow instance
│ Leaking: UNKNOWN
│ Retaining 15.3 kB in 300 objects
│ mContext instance of android.view.ContextThemeWrapper, wrapping activity
│ with mDestroyed = false
│ Window#mDestroyed is false
│ ↓ PhoneWindow.mDecor
│ ~~~~~~
╰→ com.android.internal.policy.DecorView instance
Leaking: YES (ObjectWatcher was watching this because com.android.
internal.policy.DecorView received View#onDetachedFromWindow() callback)
Retaining 4.7 kB in 42 objects
key = f381c0b5-587b-4d68-b453-be1c851ce257
watchDurationMillis = 31367
retainedDurationMillis = 26366
View not part of a window view hierarchy
View.mAttachInfo is null (view detached)
View.mWindowAttachCount = 1
mContext instance of android.view.ContextThemeWrapper, wrapping activity
with mDestroyed = false
为什么会漏水,我该如何解决?
在尝试找出问题几个小时后,当我在调用 mAlertDialog.dismiss();
mAlertDialog
设置为 null
时,内存泄漏不再发生
mAlertDialog.dismiss();
mAlertDialog = null;
Toast.makeText(LoginActivity.this, "Authentication failed.",Toast.LENGTH_SHORT).show();
我不知道为什么会这样...但它阻止了泄漏的发生。