SharedPreferences在onCreateOptionsMenu中失效,如何仅首次显示ShowcaseView?
解决ShowcaseView仅在应用首次启动显示的问题
看起来你遇到的核心问题是SharedPreferences没有被正确持久化,导致每次重启应用后isFirstTime又回到默认的true。我帮你分析下问题根源,再给出修复后的代码:
问题根源分析
- SharedPreferences名称错误:你用了
String.valueOf(getApplicationContext())作为SP文件名,这个值是Context对象的字符串表示,每次应用启动可能会变化,导致无法读取之前保存的状态。 - 提交时机冗余:代码末尾额外调用的
editor.commit()虽然不会覆盖已有值,但属于多余操作;另外commit()是同步操作,不如apply()高效。 - 菜单加载时机问题:50ms的延迟可能太短,菜单还没完全绘制完成,导致
findViewById(R.id.item_sync)返回null,ShowcaseView无法正常显示。
修复后的完整代码
private SharedPreferences pref; private SharedPreferences.Editor editor; private FancyShowCaseView mFancyShowCaseView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_activity_layout); // 用固定字符串作为SP名称,确保每次启动都访问同一个存储文件 pref = getSharedPreferences("MyAppLaunchPrefs", Context.MODE_PRIVATE); editor = pref.edit(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_contact, menu); // 判断是否为首次启动 if (pref.getBoolean("isFirstTime", true)) { // 立即标记为非首次启动,避免重复触发 editor.putBoolean("isFirstTime", false).apply(); // 延长延迟时间,确保菜单完全绘制完成 new Handler(Looper.getMainLooper()).postDelayed(() -> { View syncMenuItem = findViewById(R.id.item_sync); // 增加空检查,防止菜单未加载完成导致空指针 if (syncMenuItem != null) { mFancyShowCaseView = new FancyShowCaseView.Builder(ContactTabActivity.this) .focusOn(syncMenuItem) .focusCircleRadiusFactor(1.5) .focusBorderSize(15) .focusBorderColor(Color.parseColor("#FFA64D")) .customView(R.layout.case_view_sync, view -> { view.findViewById(R.id.btnOke).setOnClickListener(v -> { mFancyShowCaseView.removeView(); }); }) .closeOnTouch(false) .build(); mFancyShowCaseView.show(); } }, 200); } return super.onCreateOptionsMenu(menu); }
关键修改点说明
- 固定SP名称:使用
"MyAppLaunchPrefs"这种固定字符串作为SP文件名,保证每次启动都能读取到之前保存的状态。 - 改用
apply()提交:apply()是异步提交,不会阻塞主线程,比同步的commit()更适合这种场景。 - 调整延迟时间:把50ms改为200ms,给菜单足够的绘制时间,避免找不到菜单项的问题。
- 增加空检查:防止菜单未加载完成时出现NullPointerException。
- SP初始化移到
onCreate:符合Activity生命周期规范,避免在onCreateOptionsMenu重复初始化。
如果之后需要测试重新显示ShowcaseView,只需调用editor.putBoolean("isFirstTime", true).apply()即可重置状态。
内容的提问来源于stack exchange,提问作者Asqa
相关产品推荐
相关产品推荐

