解决Android多语言应用旋转时自动恢复默认语言的问题
Fix for Language Reset on Device Rotation in Android Language Switcher
Let's tackle your issue head-on: the language resets to English on rotation because your locale changes aren't being properly persisted across Activity recreation, and you're using the wrong lifecycle methods to save/restore state. Here's the complete fixed code with explanations of key changes:
Fixed LanguageActivity Code
import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Build; import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.List; import java.util.Locale; public class LanguageActivity extends AppCompatActivity implements LocaleListener { private List<Languages> languagesList = new ArrayList<>(); private RecyclerView recyclerView; private LanguageAdapter languageAdapter; private String selectedLang; private SharedPreferences prefs; private static final String PREFS_LANG_KEY = "selected_language"; private static final String DEFAULT_LANG = "en"; // Set your actual default here @Override protected void attachBaseContext(Context newBase) { // Apply saved locale before Activity creation (critical for Android N+) prefs = newBase.getSharedPreferences("LanguagePrefs", MODE_PRIVATE); selectedLang = prefs.getString(PREFS_LANG_KEY, DEFAULT_LANG); super.attachBaseContext(updateLocale(newBase, selectedLang)); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_language); // Initialize RecyclerView RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(this, 3); recyclerView = findViewById(R.id.recycler_view); languageAdapter = new LanguageAdapter(languagesList); recyclerView.setLayoutManager(mLayoutManager); languageAdapter.setLocaleListener(this); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.setAdapter(languageAdapter); prepareLanguageData(); // Restore state if Activity is being recreated if (savedInstanceState != null) { selectedLang = savedInstanceState.getString(PREFS_LANG_KEY, DEFAULT_LANG); setLocale(selectedLang); } else { // Apply saved language on first launch setLocale(selectedLang); } } private void prepareLanguageData() { languagesList.add(new Languages("English", "en")); // Add language code alongside display name languagesList.add(new Languages("العَرَبِيَّة", "ar")); languageAdapter.notifyDataSetChanged(); } @Override public void setLocale(String lang) { selectedLang = lang; // Validate locale support boolean isSupported = false; for (Locale locale : Locale.getAvailableLocales()) { if (lang.equals(locale.getLanguage())) { // Check language code instead of full locale string isSupported = true; break; } } if (isSupported) { // Update app locale Context updatedContext = updateLocale(this, lang); // Persist the selected language to SharedPreferences prefs.edit().putString(PREFS_LANG_KEY, lang).apply(); // Refresh the Activity to apply new locale recreate(); } else { Toast.makeText(this, "Language not supported", Toast.LENGTH_SHORT).show(); } } private Context updateLocale(Context context, String langCode) { Locale newLocale = new Locale(langCode); Locale.setDefault(newLocale); android.content.res.Configuration config = new android.content.res.Configuration(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { config.setLocale(newLocale); return context.createConfigurationContext(config); } else { config.locale = newLocale; context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); return context; } } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { // Save selected language to bundle for recreation outState.putString(PREFS_LANG_KEY, selectedLang); super.onSaveInstanceState(outState); } }
Key Fixes & Explanations
- Persistent Storage with SharedPreferences: We now save the selected language to SharedPreferences, so it persists across app restarts and device rotations.
- attachBaseContext Override: This is critical for Android 7.0+ (API 24+), as it applies the locale before the Activity is fully created, preventing the system from resetting to default during configuration changes.
- Corrected onSaveInstanceState: We use the standard
onSaveInstanceState(Bundle outState)(not the PersistableBundle overload, which isn't triggered by default) to save the selected language temporarily during rotation. - Language Code Validation: Changed from checking full locale strings to just language codes (e.g., "en", "ar") for more reliable validation.
- Recreate Activity After Locale Change: Calling
recreate()ensures the UI immediately reflects the new language, and avoids inconsistencies during rotation. - Updated prepareLanguageData: Added language codes directly to the Languages model (you'll need to update your
Languagesclass to hold both display name and language code) so the adapter can pass the correct code tosetLocale().
Additional Notes
- Update your
Languagesclass to include a language code field (e.g.,private String langCode;) and modify yourLanguageAdapterto pass this code when an item is clicked. - For consistency across all Activities, consider creating a base
BaseActivityclass that handles the locale setup inattachBaseContext, so you don't have to repeat this code in every Activity.
内容的提问来源于stack exchange,提问作者SHEHZAD SULAIMAN
相关产品推荐
相关产品推荐

