App 首次安裝啟動顯示引導頁,之後每次啟動直接進入主頁。
final boolean isFirst = prefs.getBoolean("isFirstIn", true);
// 後續在 GuideActivity 修改 prefs,但 isFirst 已是編譯期常量,不會重新讀取
修正:不要用 `final` 修飾讀取的布林值,或在 `onResume` / 決策瞬間**即時讀取**。
Android 多進程模式下 `SharedPreferences` 一致性無保障。單進程 App 直接用 `Context.MODE_PRIVATE`。
editor.putBoolean("isFirstIn", false);
editor.apply(); // 必須調用,否則不生效
public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 無需 setContentView,直接決策跳轉
SharedPreferences sp = getSharedPreferences("app_config", MODE_PRIVATE);
boolean isFirst = sp.getBoolean("is_first_launch", true);
Intent intent = new Intent(this, isFirst ? GuideActivity.class : MainActivity.class);
startActivity(intent);
finish();
}
}
btnStart.setOnClickListener(v -> {
SharedPreferences sp = getSharedPreferences("app_config", MODE_PRIVATE);
sp.edit().putBoolean("is_first_launch", false).apply();
startActivity(new Intent(this, MainActivity.class));
finish();
});
新專案建議用 Preferences DataStore,協程流式 API、主執行緒安全、自動處理異步寫入:
// 依賴: implementation "androidx.datastore:datastore-preferences:1.0.0"
val Context.dataStore: DataStore by preferencesDataStore(name = "app_config")
// 讀取
val isFirstFlow = dataStore.data.map { it[booleanPreferencesKey("is_first_launch")] ?: true }
// 寫入
scope.launch { dataStore.edit { it[booleanPreferencesKey("is_first_launch")] = false } }