升级compileSDK 31后Contextual Action Mode偶尔不显示问题
问题背景
升级至compileSdkVersion 31(Android 12)后,部分用户反馈RecyclerView列表条目选中后,带编辑按钮的**上下文操作栏(CAB)**未显示,但条目已处于选中状态。重启应用后问题暂时消失,但一段时间后会复现。
日志显示onCreateActionMode、onPrepareActionMode等核心方法均正常调用,状态栏也成功变为灰色,说明业务逻辑已执行。通过LayoutInspector分析发现:异常时CAB的宽高被计算为0dp,正常状态下则有正确的尺寸值。
可能原因
Android 12对窗口布局、ActionMode的显示逻辑做了调整,尤其是在多窗口切换、窗口焦点变化或系统UI状态更新时,可能出现CAB布局未正确测量/挂载到窗口层级的情况。此外,startSupportActionMode返回的ActionMode实例虽非空,但系统可能未完成其UI组件的初始化流程,导致宽高异常。
解决方案
方案1:延迟触发CAB重布局
在启动ActionMode后,延迟一段时间强制触发布局更新,给系统足够时间完成窗口层级的初始化:
// 替换原启动ActionMode的代码段 mActionMode = activity.startSupportActionMode(mActionModeCallback); if(mActionMode != null) { mActionMode.setTitle(R.string.options); // 延迟100ms触发重布局,确保系统完成窗口层级更新 new Handler(Looper.getMainLooper()).postDelayed(() -> { if (mActionMode != null) { mActionMode.invalidate(); activity.getWindow().getDecorView().requestLayout(); } }, 100); HyperLog.i(TAG, "onItemClick - Starting the action mode and setting the title Options."); }
方案2:移除不必要的重复invalidate()调用
原代码中启动ActionMode后立即调用mActionMode.invalidate(),可能导致系统重复触发布局计算,反而引发异常。尝试移除该调用:
mActionMode = activity.startSupportActionMode(mActionModeCallback); if(mActionMode != null) { mActionMode.setTitle(R.string.options); // 移除此处的invalidate()调用 // mActionMode.invalidate(); HyperLog.i(TAG, "onItemClick - Starting the action mode and setting the title Options."); }
方案3:修复主题中ActionMode的尺寸配置
检查应用主题,确保Android 12下ActionMode的尺寸属性配置正确,避免因主题冲突导致CAB无法正常显示:
在styles.xml中添加或修改:
<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar"> <item name="actionModeStyle">@style/Widget.App.ActionMode</item> </style> <style name="Widget.App.ActionMode" parent="Widget.MaterialComponents.ActionMode"> <!-- 强制设置ActionMode的最小高度为ActionBar标准高度 --> <item name="android:height">?attr/actionBarSize</item> <item name="android:minHeight">?attr/actionBarSize</item> </style>
方案4:监听窗口焦点,恢复异常状态的CAB
当应用窗口重新获取焦点时,检查是否有选中条目,若CAB未初始化则重新启动:
// 在Fragment的onResume中添加检查逻辑 @Override public void onResume() { super.onResume(); int checkedCount = flexibleAdapter.getSelectedItemCount(); if (checkedCount > 0 && mActionMode == null) { mActionMode = activity.startSupportActionMode(mActionModeCallback); if(mActionMode != null) { mActionMode.setTitle(R.string.options); mActionMode.invalidate(); } } } // 监听窗口焦点变化 activity.getWindow().getDecorView().setOnWindowFocusChangeListener((hasFocus) -> { if (hasFocus) { int checkedCount = flexibleAdapter.getSelectedItemCount(); if (checkedCount > 0 && mActionMode == null) { mActionMode = activity.startSupportActionMode(mActionModeCallback); if(mActionMode != null) { mActionMode.setTitle(R.string.options); mActionMode.invalidate(); } } } });
验证建议
优先尝试方案1和方案2,这两个方案直接针对布局计算异常的核心场景;若问题仍未解决,再排查主题配置和窗口焦点相关的方案3、4。
内容的提问来源于stack exchange,提问作者chrisonline

