WindowManagerGlobal.sDefaultWindowManager内存泄漏
WindowManagerGlobal.sDefaultWindowManager memory leak
我正在使用导航组件,并且在退出应用程序时发生内存泄漏..
这是 LeakCanary logcat
┬───
│ GC Root: System class
│
├─ android.view.WindowManagerGlobal class
│ Leaking: NO (a class is never leaking)
│ ↓ static WindowManagerGlobal.sDefaultWindowManager
│ ~~~~~~~~~~~~~~~~~~~~~
├─ android.view.WindowManagerGlobal instance
│ Leaking: UNKNOWN
│ ↓ WindowManagerGlobal.mViews
│ ~~~~~~
├─ java.util.ArrayList instance
│ Leaking: UNKNOWN
│ ↓ ArrayList.elementData
│ ~~~~~~~~~~~
├─ java.lang.Object[] array
│ Leaking: UNKNOWN
│ ↓ Object[].[0]
│ ~~~
├─ android.widget.LinearLayout instance
│ Leaking: YES (View.mContext references a destroyed activity)
│ mContext instance of .....ui.MainActivity with mDestroyed = true
│ View#mParent is set
│ View#mAttachInfo is not null (view attached)
│ View.mWindowAttachCount = 1
│ ↓ LinearLayout.mContext
╰→ .....ui.MainActivity instance
Leaking: YES (ObjectWatcher was watching this because .....ui.MainActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
key = 4a23bf94-97b5-4f44-87d2-6f9a59fc053f
watchDurationMillis = 5135
retainedDurationMillis = 134
我的activity代码:
public class MainActivity extends AppCompatActivity {
private NavController mNavController;
private AppBarConfiguration mAppBarConfiguration;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupStatusBar();
// Reset the shared prefs values only for the first launch of the app.
PreferenceManager.setDefaultValues(this, R.xml.settings, false);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
// return for API-19+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
return;
// Customize Activity to not overlap with the bottom software buttons navigation bar (back, home, & menu)
boolean hasMenuKey = ViewConfiguration.get(this).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
if (!hasMenuKey && !hasBackKey) { // check if this device has a bottom navigation bar
try {
ConstraintLayout rootLayout = findViewById(R.id.activity_root);
int NAVIGATION_BAR_HEIGHT = 70;
rootLayout.getLayoutParams().height = rootLayout.getHeight() - NAVIGATION_BAR_HEIGHT;
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void setupStatusBar() {
// Making status bar transparent and overlapping with the activity
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
getWindow().setFlags(FLAG_LAYOUT_NO_LIMITS, FLAG_LAYOUT_NO_LIMITS);
}
public void setupActionBar() {
mNavController = Navigation.findNavController(this, R.id.nav_host_fragment);
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.mainFragment, R.id.readFragment) // remove up button from all these fragments
.build();
NavigationUI.setupActionBarWithNavController(this, mNavController, mAppBarConfiguration);
}
@Override
public boolean onSupportNavigateUp() {
return NavigationUI.navigateUp(mNavController, mAppBarConfiguration) // navigateUp tries to pop the back stack
|| super.onSupportNavigateUp();
}
@Override
protected void onDestroy() {
super.onDestroy();
getWindow().clearFlags( WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
mAppBarConfiguration = null;
mNavController = null;
}
}
我试图清除我在 onDestroy()
中设置的 window 标志,甚至试图将 mAppBarConfiguration
和 mNavController
设置为空,但没有成功。
同样在主片段中,我在 onDestroyView()
中将 mContext
设置为 null
注意:我在 xml 布局中没有任何 LinearLayout
。
我设置activity在导航组件的某些片段中动态支持ActionBar;设置操作栏后,我调用 setupActionBar()
以使用导航组件调整新设置的操作栏:
片段中
Toolbar toolbar = requireView().findViewById(R.id.toolbar);
((MainActivity) requireActivity()).setSupportActionBar(toolbar);
((MainActivity) requireActivity()).setupActionBar();
我通过在 activity 的 onDestroy()
中将操作栏设置回 null 解决了 WindowManagerGlobal.sDefaultWindowManager
内存泄漏问题。
@Override
protected void onDestroy() {
super.onDestroy();
setSupportActionBar(null);
}
我正在使用导航组件,并且在退出应用程序时发生内存泄漏..
这是 LeakCanary logcat
┬───
│ GC Root: System class
│
├─ android.view.WindowManagerGlobal class
│ Leaking: NO (a class is never leaking)
│ ↓ static WindowManagerGlobal.sDefaultWindowManager
│ ~~~~~~~~~~~~~~~~~~~~~
├─ android.view.WindowManagerGlobal instance
│ Leaking: UNKNOWN
│ ↓ WindowManagerGlobal.mViews
│ ~~~~~~
├─ java.util.ArrayList instance
│ Leaking: UNKNOWN
│ ↓ ArrayList.elementData
│ ~~~~~~~~~~~
├─ java.lang.Object[] array
│ Leaking: UNKNOWN
│ ↓ Object[].[0]
│ ~~~
├─ android.widget.LinearLayout instance
│ Leaking: YES (View.mContext references a destroyed activity)
│ mContext instance of .....ui.MainActivity with mDestroyed = true
│ View#mParent is set
│ View#mAttachInfo is not null (view attached)
│ View.mWindowAttachCount = 1
│ ↓ LinearLayout.mContext
╰→ .....ui.MainActivity instance
Leaking: YES (ObjectWatcher was watching this because .....ui.MainActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
key = 4a23bf94-97b5-4f44-87d2-6f9a59fc053f
watchDurationMillis = 5135
retainedDurationMillis = 134
我的activity代码:
public class MainActivity extends AppCompatActivity {
private NavController mNavController;
private AppBarConfiguration mAppBarConfiguration;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupStatusBar();
// Reset the shared prefs values only for the first launch of the app.
PreferenceManager.setDefaultValues(this, R.xml.settings, false);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
// return for API-19+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
return;
// Customize Activity to not overlap with the bottom software buttons navigation bar (back, home, & menu)
boolean hasMenuKey = ViewConfiguration.get(this).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
if (!hasMenuKey && !hasBackKey) { // check if this device has a bottom navigation bar
try {
ConstraintLayout rootLayout = findViewById(R.id.activity_root);
int NAVIGATION_BAR_HEIGHT = 70;
rootLayout.getLayoutParams().height = rootLayout.getHeight() - NAVIGATION_BAR_HEIGHT;
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void setupStatusBar() {
// Making status bar transparent and overlapping with the activity
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
getWindow().setFlags(FLAG_LAYOUT_NO_LIMITS, FLAG_LAYOUT_NO_LIMITS);
}
public void setupActionBar() {
mNavController = Navigation.findNavController(this, R.id.nav_host_fragment);
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.mainFragment, R.id.readFragment) // remove up button from all these fragments
.build();
NavigationUI.setupActionBarWithNavController(this, mNavController, mAppBarConfiguration);
}
@Override
public boolean onSupportNavigateUp() {
return NavigationUI.navigateUp(mNavController, mAppBarConfiguration) // navigateUp tries to pop the back stack
|| super.onSupportNavigateUp();
}
@Override
protected void onDestroy() {
super.onDestroy();
getWindow().clearFlags( WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
mAppBarConfiguration = null;
mNavController = null;
}
}
我试图清除我在 onDestroy()
中设置的 window 标志,甚至试图将 mAppBarConfiguration
和 mNavController
设置为空,但没有成功。
同样在主片段中,我在 onDestroyView()
mContext
设置为 null
注意:我在 xml 布局中没有任何 LinearLayout
。
我设置activity在导航组件的某些片段中动态支持ActionBar;设置操作栏后,我调用 setupActionBar()
以使用导航组件调整新设置的操作栏:
片段中
Toolbar toolbar = requireView().findViewById(R.id.toolbar);
((MainActivity) requireActivity()).setSupportActionBar(toolbar);
((MainActivity) requireActivity()).setupActionBar();
我通过在 activity 的 onDestroy()
中将操作栏设置回 null 解决了 WindowManagerGlobal.sDefaultWindowManager
内存泄漏问题。
@Override
protected void onDestroy() {
super.onDestroy();
setSupportActionBar(null);
}