Oreo设备Toolbar变空问题:同代码在Nougat及以下版本正常
嘿,这个问题我之前帮同事排查Oreo适配的时候碰到过!同一套代码在Nougat及以下正常,切换Fragment就把Toolbar的内容和汉堡图标搞没,核心是Oreo(API 26)开始对AppCompat的Toolbar生命周期管理变严格了,给你一步步拆解原因和解决办法:
Oreo之前的系统对AppCompatActivity的Toolbar实例兼容性更宽松,但从Oreo开始,如果你在Fragment里错误地重复初始化Toolbar、覆盖Activity的Toolbar配置,或者没有同步DrawerToggle的状态,就会导致原Toolbar的标题、图标等状态被清空。
1. 禁止在Fragment中重复设置setSupportActionBar
很多开发者会习惯在Fragment里也调用setSupportActionBar(toolbar),这会直接覆盖Activity的Toolbar实例,Oreo开始这种操作会彻底丢失原Toolbar的状态。正确的做法是:只在Activity里初始化Toolbar和DrawerToggle,Fragment通过Activity的实例来修改Toolbar内容。
示例代码:
// Activity中只做一次初始化(作为全局配置) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化Toolbar并绑定到Activity Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); // 绑定DrawerToggle并同步状态 DrawerLayout drawer = findViewById(R.id.drawer_layout); this.drawerToggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.drawer_open, R.string.drawer_close); drawer.addDrawerListener(drawerToggle); drawerToggle.syncState(); } // Fragment中仅修改Toolbar内容,不重新绑定 @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); AppCompatActivity parentActivity = (AppCompatActivity) getActivity(); if (parentActivity != null && parentActivity.getSupportActionBar() != null) { // 设置Fragment对应的标题 parentActivity.getSupportActionBar().setTitle("我的Fragment"); // 如果需要显示返回箭头,单独设置(不要重新创建Toggle) parentActivity.getSupportActionBar().setDisplayHomeAsUpEnabled(true); } }
2. 切换Fragment后重新同步DrawerToggle状态
汉堡图标消失大概率是Toggle的状态没有和DrawerLayout同步,在Fragment切换完成后(比如Activity的onResume或者Fragment的onResume),手动调用syncState()即可。
示例:
// 把DrawerToggle设为Activity的成员变量,方便后续调用 private ActionBarDrawerToggle drawerToggle; // 在Activity的onResume中同步状态 @Override protected void onResume() { super.onResume(); if (drawerToggle != null) { drawerToggle.syncState(); } } // 或者在Fragment的onViewCreated中补充同步 @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); MainActivity parent = (MainActivity) getActivity(); if (parent != null && parent.drawerToggle != null) { parent.drawerToggle.syncState(); } }
3. 更新AppCompat库版本
旧版本的AppCompat库可能存在Oreo适配bug,确保你的依赖版本足够新:
// AndroidX版本(推荐) implementation 'androidx.appcompat:appcompat:1.6.1' // 旧Support库版本(不建议,优先迁移到AndroidX) implementation 'com.android.support:appcompat-v7:28.0.0'
4. 避免不当调用invalidateOptionsMenu()
如果Fragment里调用了invalidateOptionsMenu()刷新菜单,可能会连带重置Toolbar的图标状态。如果必须调用,记得在调用后重新同步DrawerToggle的状态。
可以在Activity和Fragment的生命周期方法里打印Toolbar的哈希值,确认切换Fragment后是否是同一个实例:
// Activity中打印 Log.d("ToolbarDebug", "Activity Toolbar ID: " + toolbar.hashCode()); // Fragment中打印 Log.d("ToolbarDebug", "Fragment 获取的Toolbar ID: " + ((AppCompatActivity) getActivity()).getSupportActionBar().hashCode());
如果两个哈希值不一样,说明Fragment里误创建了新的Toolbar实例,覆盖了原有的。
内容的提问来源于stack exchange,提问作者Mohit Ajwani

