You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DrawerLayout菜单项仅更新一次后返回Null问题求助

问题描述

我在DrawerLayout导航菜单里添加了一个选项,用来切换NavMenuItemView的文本为“启用深色模式”或“禁用深色模式”,该选项关联SharedPreference(即editor变量)。首次切换时功能正常,能根据当前主题模式显示对应文本;但后续切换时,仅能切换主题颜色,文本变为空白,且night变量返回Null。我尝试在onCreate中调用invalidateOptionsMenu,以及将更新逻辑从onCreateOptionsMenu移至onCreate,均未改变该异常表现。

相关代码

private Toolbar toolbar;
private DrawerLayout drawerLayout;
private NavigationView navigationView;
private NavigationMenuItemView night;
Menu menu;
String imagesDir;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ActivityMainBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());

    toolbar = (Toolbar) findViewById(R.id.main_toolbar);
    setSupportActionBar(toolbar);
    drawerLayout = (DrawerLayout) findViewById(R.id.drawerlayout);
    navigationView = (NavigationView) findViewById(R.id.nav_view);
    night = drawerLayout.findViewById(R.id.NightMode);
    navigationView.bringToFront();
    navigationView.setNavigationItemSelectedListener(this);

    ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.open,R.string.close);
    drawerLayout.addDrawerListener(actionBarDrawerToggle);
    actionBarDrawerToggle.syncState();
}

@SuppressLint("RestrictedApi")
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    this.menu = menu;
    drawerLayout = (DrawerLayout) findViewById(R.id.drawerlayout);
    night = drawerLayout.findViewById(R.id.NightMode);
    if (night != null) {
        if (SplashActivity.isDarkModeOn) {
            night.setTitle("Disable Dark Mode");
        } else {
            night.setTitle("Enable Dark Mode");
        }
    }else {
        Toast.makeText(this, "null", Toast.LENGTH_SHORT).show();
    }
    return true;
}

@Override
@SuppressLint("RestrictedApi")
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    int id = item.getItemId();
    switch (id){
        case R.id.NightMode:
            night = drawerLayout.findViewById(R.id.NightMode);
            if (night != null){
                if (SplashActivity.isDarkModeOn) {
                    night.setTitle("Disable Dark Mode");
                    SplashActivity.editor.putBoolean(
                            "isDarkModeOn", false);
                    SplashActivity.editor.apply();
                    AppCompatDelegate
                            .setDefaultNightMode(
                                    AppCompatDelegate
                                            .MODE_NIGHT_NO);
                }
                else {
                    night.setTitle("Enable Dark Mode");
                    SplashActivity.editor.putBoolean(
                            "isDarkModeOn", true);
                    SplashActivity.editor.apply();
                    AppCompatDelegate
                            .setDefaultNightMode(
                                    AppCompatDelegate
                                            .MODE_NIGHT_YES);
                }
            }
            break;
    }
    drawerLayout.closeDrawer(GravityCompat.START);
    return true;
}

解决方案

核心问题分析

  1. 直接操作NavMenuItemView实例失效:主题切换后,NavigationView会重新渲染菜单布局,之前通过findViewById获取的night实例会变成无效引用,导致后续调用时返回Null。
  2. 状态未同步更新:切换主题后,SplashActivity.isDarkModeOn的静态变量没有及时反转,导致判断逻辑与实际状态不符。

修改后的代码实现

private Toolbar toolbar;
private DrawerLayout drawerLayout;
private NavigationView navigationView;
Menu menu;
String imagesDir;
private static final String DARK_MODE_KEY = "isDarkModeOn";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = ActivityMainBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());

    toolbar = findViewById(R.id.main_toolbar);
    setSupportActionBar(toolbar);
    drawerLayout = findViewById(R.id.drawerlayout);
    navigationView = findViewById(R.id.nav_view);
    
    // 从SharedPreference同步初始状态
    SplashActivity.isDarkModeOn = SplashActivity.editor.getBoolean(DARK_MODE_KEY, false);
    
    navigationView.bringToFront();
    navigationView.setNavigationItemSelectedListener(this);

    ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open, R.string.close);
    drawerLayout.addDrawerListener(actionBarDrawerToggle);
    actionBarDrawerToggle.syncState();
    
    // 初始化菜单文本
    updateNightModeText();
}

// 封装菜单文本更新逻辑
private void updateNightModeText() {
    Menu navMenu = navigationView.getMenu();
    MenuItem nightModeItem = navMenu.findItem(R.id.NightMode);
    if (nightModeItem != null) {
        nightModeItem.setTitle(SplashActivity.isDarkModeOn ? "禁用深色模式" : "启用深色模式");
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    this.menu = menu;
    updateNightModeText();
    return true;
}

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    int id = item.getItemId();
    switch (id) {
        case R.id.NightMode:
            // 反转深色模式状态
            SplashActivity.isDarkModeOn = !SplashActivity.isDarkModeOn;
            // 更新SharedPreference
            SplashActivity.editor.putBoolean(DARK_MODE_KEY, SplashActivity.isDarkModeOn);
            SplashActivity.editor.apply();
            // 切换主题
            AppCompatDelegate.setDefaultNightMode(
                    SplashActivity.isDarkModeOn ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
            // 更新菜单文本
            updateNightModeText();
            break;
    }
    drawerLayout.closeDrawer(GravityCompat.START);
    return true;
}

关键优化点

  • 通过Menu对象操作菜单项:不再直接获取NavMenuItemView,而是通过navigationView.getMenu()获取菜单实例,再通过findItem定位目标选项,避免View实例失效问题。
  • 同步状态变量:切换主题时直接反转SplashActivity.isDarkModeOn的值,确保判断逻辑与实际状态一致。
  • 封装更新逻辑:将菜单文本更新代码抽成独立方法,避免重复代码,方便调用。

内容的提问来源于stack exchange,提问作者EagleGrant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 05:30:53