You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决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 Languages class to hold both display name and language code) so the adapter can pass the correct code to setLocale().

Additional Notes

  • Update your Languages class to include a language code field (e.g., private String langCode;) and modify your LanguageAdapter to pass this code when an item is clicked.
  • For consistency across all Activities, consider creating a base BaseActivity class that handles the locale setup in attachBaseContext, so you don't have to repeat this code in every Activity.

内容的提问来源于stack exchange,提问作者SHEHZAD SULAIMAN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:24:39