问题描述
我正在使用导航组件,并且在退出应用程序时遇到内存泄漏。
这是LeakCanary日志猫
┬───
│ 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
我的活动代码:
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()
中设置的窗口标志,甚至试图将mAppBarConfiguration
和mNavController
设置为null,但没有成功。
还在主片段中,我在mContext
中将onDestroyView()
设置为null
注意:我在xml布局中没有任何LinearLayout
。
解决方法
我在导航组件的某些片段中动态设置了活动支持ActionBar。设置好动作栏后,我调用setupActionBar()
以便通过导航组件调整新设置的动作栏:
片段
Toolbar toolbar = requireView().findViewById(R.id.toolbar);
((MainActivity) requireActivity()).setSupportActionBar(toolbar);
((MainActivity) requireActivity()).setupActionBar();
我通过在活动WindowManagerGlobal.sDefaultWindowManager
中将操作栏设置回null来解决了onDestroy()
的内存泄漏。
@Override
protected void onDestroy() {
super.onDestroy();
setSupportActionBar(null);
}