迁移到 androidX 后,在运行时以编程方式更改本地化不再适用于 pre-Oreo sdk 26

Changing Localization programatically during runtime no longer working on pre-Oreo sdk 26 after migrating to androidX

我能够使用此 article 中解释的方法在运行时以编程方式更改本地化。我能够更改应用程序的语言。 + 布局方向 + 工具栏语言。

这是我的代码:

build.gradle

 buildTypes {
        debug {
            pseudoLocalesEnabled true
        }
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.jakewharton:process-phoenix:2.0.0'
}

public class App extends Application {

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleManager.setLocale(base));
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LocaleManager.setLocale(this);
        if (Build.VERSION.SDK_INT >= 26) {
            ProcessPhoenix.triggerRebirth(this); //An activity must have a category of Default in Manifest!
        }
    }
}

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(Build.VERSION.SDK_INT>=26) {
            LocaleManager.setLocale(this);
        }
        startActivity(new Intent(this,MainActivity.class));
        finish();
    }
}

public class LocaleManager {
private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
private static final String DEFAULT_LANGUAGE = "en";

public static Context setLocale(Context c) {
    return setNewLocale(c, getLanguage(c));
}

public static Context setNewLocale(Context c, String language) {
    persistLanguage(c, language);
    return updateResources(c, language);
}

public static String getLanguage(Context c) {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(c);
    return preferences.getString(SELECTED_LANGUAGE, DEFAULT_LANGUAGE);
}

public static void persistLanguage(Context c, String language) {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(c);
    SharedPreferences.Editor editor = preferences.edit();
    editor.putString(SELECTED_LANGUAGE, language);
    editor.commit(); 
}

private static Context updateResources(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Resources res = context.getResources();
    Configuration config = new Configuration(res.getConfiguration());

    if(Build.VERSION.SDK_INT >= 17) {
        config.setLocale(locale);
        res.updateConfiguration(config, res.getDisplayMetrics());
    }
    return context;
}

}


public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

//Change English to arabic when user clicked the button.
public void changeLanguage(View view) {
    LocaleManager.persistLanguage(this ,"ar");
    LocaleManager.setLocale(this);
    ProcessPhoenix.triggerRebirth(this); //An activity must have a category of Default in Manifest!

问题: 在我迁移到 androidX 之前,这段代码一直运行良好。现在,它仅适用于 Android Oreo+ 的设备。我在迁移到 androidX 之前检查了一个备份版本,它运行良好。我在这里遗漏了什么吗?

正在将 implementation of 'androidx.appcompat:appcompat:1.1.0' 更改为版本 1.0.0

并保持 'androidx.constraintlayout:constraintlayout:1.1.3' 到版本 1.1.3

解决问题。

此外,如果您使用实现 'com.google.android.material:material:1.1.0',请将其更改为版本 1.0.0

使用 SDK 30 (2020) 的运行时本地化完整解决方案

  • 这是在从 OS 版本 19 到 30 的模拟器上测试的。它 解决了最近报告的有关 OS 的问题 Marshmallow + Nougat 并使用最新的 appcompat + material + 约束布局依赖性。
  • 它还处理 RTL 支持的布局方向。

步骤:

  1. 使用适当的限定符为您希望应用程序支持的不同语言创建字符串 XML 文件。就我而言,我使用英语和阿拉伯语限定符来测试 Layout RTL。

  2. 将此行 pseudoLocalesEnabled true 添加到模块 build.gradle 下的 android->build types in both debug and release.

  3. 添加此依赖项以便能够轻松重启您的应用程序:

    '执行'com.jakewharton:process-phoenix:2.0.0'

  4. 创建以下“LocaleManager”java class 来处理将所选区域设置保存到共享首选项并应用必要的运行时区域设置更改。

    public class LocaleManager {
    private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
    private static final String DEFAULT_LANGUAGE = "en";
    
    public static Context setLocale(Context c) {
        return setNewLocale(c, getLanguage(c));
    }
    
    public static Context setNewLocale(Context c, String language) {
        persistLanguage(c, language);
        return updateResources(c, language);
    }
    
    public static String getLanguage(Context c) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(c);
        return preferences.getString(SELECTED_LANGUAGE, DEFAULT_LANGUAGE);
    }
    
    public static void persistLanguage(Context c, String language) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(c);
        SharedPreferences.Editor editor = preferences.edit();
        editor.putString(SELECTED_LANGUAGE, language);
        editor.commit(); //U must use Commit and not apply, to avoid opening a new thread, causing a delayed writting in a separate thread!
    }
    
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
    
        Resources res = context.getResources();
        Configuration config = new Configuration(res.getConfiguration());
    
        if(Build.VERSION.SDK_INT >= 17) {
            config.setLocale(locale);
            res.updateConfiguration(config, res.getDisplayMetrics());
        }
        return context;
    }
    
    }
    
  5. 创建以下扩展应用程序的“应用程序”class。确保您的 MainActivity 或启动器 Activity 在 Manifest 中有一个 Default 类别。

    public class App extends Application {
    
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleManager.setLocale(base));
        Log.e("lang", LocaleManager.getLanguage(base));
    }
    
    //Handles screen rotation only up till API 28 pie
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LocaleManager.setLocale(this);
        if (Build.VERSION.SDK_INT >= 26) {
            ProcessPhoenix.triggerRebirth(this); //An activity must have a category of Default in Manifest!
        }
    }
    }
    

清单

<activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

<application
        android:name=".App"
        
  1. 在 MainActivity 中创建一个切换语言的按钮,如下所示:

    public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
    //Change English to arabic when user clicked the button.
    public void changeLanguageToArabic(View view) {
        LocaleManager.persistLanguage(this, "ar");
        LocaleManager.setLocale(this);
        ProcessPhoenix.triggerRebirth(this); //An activity must have a category of Default in Manifest!
    }
    
    
    public void goToSecondActivity(View view) {
        Intent intent = new Intent(this, MainActivity2.class);
        startActivity(intent);
    }
    

您选择的语言环境将在所有活动和重新启动您的应用程序时保持不变。