애플리케이션 내에서 언어 (로케일)를 변경 한 후 활동을 새로 고치는 방법
내 애플리케이션 사용자는 앱 설정에서 언어를 변경할 수 있습니다. 일반 언어 설정에 영향을주지 않고 응용 프로그램 내에서 언어를 변경할 수 있습니까? 이 stackoverflow 질문은 나에게 매우 유용하며 시도해 보았습니다. 언어 변경 후 새로 생성 된 활동은 변경된 새 언어로 표시되지만 현재 활동과 일시 중지 상태 인 이전에 생성 된 활동은 업데이트되지 않습니다. 나는 또한 환경 설정 변경을 즉시 적용하기 위해 많은 시간을 보냈지 만 성공하지 못했습니다. 응용 프로그램이 다시 시작되면 모든 활동이 다시 생성되므로 이제 언어가 올바르게 변경되었습니다.
android:configChanges="locale"
또한 모든 활동에 대한 매니페스트에 추가되었습니다. 또한 모든 화면을 지원합니다. 현재 활동의 onResume () 메서드에서 아무 작업도 수행하지 않았습니다. 활동을 새로 고치거나 업데이트하는 방법이 있습니까 (완료했다가 다시 시작하지 않고)? onResume () 메서드에서 할 일이 없습니까?
언어 변경 후 새로 생성 된 활동은 변경된 새 언어로 표시되지만 현재 활동 및 일시 중지 상태 인 이전에 생성 된 활동은 업데이트되지 않습니다.
Pre API 11 (Honeycomb), 기존 활동을 새 언어로 표시하는 가장 간단한 방법은 다시 시작하는 것입니다. 이런 식으로 각 리소스를 직접 다시로드하지 않아도됩니다.
private void restartActivity() {
Intent intent = getIntent();
finish();
startActivity(intent);
}
언어 기본 설정이 변경된 경우 호출을 OnSharedPreferenceChangeListener
에 등록합니다 . 내 예에서는 PreferenceActivity 만 다시 시작되지만 플래그를 설정하여 활동 재개에 대한 다른 활동을 다시 시작할 수 있어야합니다.onShredPreferenceChanged()
restartActivity()
업데이트 (@stackunderflow에게 감사드립니다) : API 11 (Honeycomb) recreate()
부터 restartActivity()
.
public class PreferenceActivity extends android.preference.PreferenceActivity implements
OnSharedPreferenceChangeListener {
// ...
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals("pref_language")) {
((Application) getApplication()).setLocale();
restartActivity();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onStop() {
super.onStop();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
}
이 주제에 대한 자세한 블로그 게시물 이 있지만 중국어로되어 있습니다. 전체 소스 코드는 github : PreferenceActivity.java에 있습니다.
manifest.xmlandroid:configChanges
에서 설정 하고 다음 과 같은 여러 언어에 대해 여러 디렉토리를 생성 한다고 상상했다면 다음 코드를 제안 할 수 있습니다 (In Activity class).values-fr OR values-nl
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// change language by onclick a button
Configuration newConfig = new Configuration();
newConfig.locale = Locale.FRENCH;
onConfigurationChanged(newConfig);
}
});
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics());
setContentView(R.layout.main);
setTitle(R.string.app_name);
// Checks the active language
if (newConfig.locale == Locale.ENGLISH) {
Toast.makeText(this, "English", Toast.LENGTH_SHORT).show();
} else if (newConfig.locale == Locale.FRENCH){
Toast.makeText(this, "French", Toast.LENGTH_SHORT).show();
}
}
이 코드를 테스트했는데 맞습니다.
문자열 리소스가 기존 로케일에 대해 이미로드되었으므로 이미 열린 활동은 새 로케일의 문자열을 사용하여 자동으로 표시되지 않습니다. 이를 해결하는 유일한 방법은 모든 문자열을 다시로드하고 뷰에서 다시 설정하는 것입니다. 일반적으로를 호출하면 setContentView(...)
이를 처리 할 수 있지만 (활동 구조에 따라 다름) 물론 뷰 상태를 잃는 부작용이 있습니다.
public void onResume() {
super.onResume();
...
if (localeHasChanged) {
setContentView(R.layout.xxx);
}
...
}
에서 매번 뷰를 다시로드하지 않고 onResume()
로케일이 변경된 경우에만 뷰를 다시로드하고 싶을 것입니다 . 뷰를 업데이트 할시기 (예 :)를 확인 localeHasChanged
하는 것은 로케일 변경 이벤트를 이전 활동에 전파하는 문제입니다. 이것은 정적 싱글 톤과 같은 상태를 사용하거나이 이벤트를 스토리지에 유지하는 것과 같은 다양한 방법으로 수행 될 수 있습니다.
로케일을 변경할 수있을 때 열 수있는 활동의 수를 최소화 할 수도 있습니다 (예 : 초기 화면 중 하나에서 선택하도록 함).
Android 4.2 (API 17)의 경우 android:configChanges="locale|layoutDirection"
AndroidManifest.xml에서 사용해야 합니다. onConfigurationchanged가 jellybean (4.2.1)을 통해 호출되지 않음을 참조하십시오.
우리가 한 방식은 브로드 캐스트를 사용하는 것입니다.
- 사용자가 언어를 변경할 때마다 브로드 캐스트를 보냅니다.
- 브로드 캐스트 수신기를에
AppActivity.onCreate()
등록하고 등록을 취소합니다.AppActivity.onDestroy()
- 에서
BroadcastReceiver.onReceive()
바로 활동을 다시 시작합니다.
AppActivity
다른 모든 활동이 하위 클래스로 분류하는 상위 활동입니다.
아래는 프로젝트 외부에서 테스트되지 않은 내 코드의 스 니펫이지만 좋은 아이디어를 제공해야합니다.
사용자가 언어를 변경할 때
sendBroadcast(new Intent("Language.changed"));
그리고 부모 활동에서
public class AppActivity extends Activity {
/**
* The receiver that will handle the change of the language.
*/
private BroadcastReceiver mLangaugeChangedReceiver;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
// Other code here
// ...
// Define receiver
mLangaugeChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
startActivity(getIntent());
finish();
}
};
// Register receiver
registerReceiver(mLangaugeChangedReceiver, new IntentFilter("Language.changed"));
}
@Override
protected void onDestroy() {
super.onDestroy();
// ...
// Other cleanup code here
// ...
// Unregister receiver
if (mLangaugeChangedReceiver != null) {
try {
unregisterReceiver(mLangaugeChangedReceiver);
mLangaugeChangedReceiver = null;
} catch (final Exception e) {}
}
}
}
또한 언어를 변경 한 활동을 새로 고칩니다 (위 활동을 하위 클래스로 분류하는 경우).
이로 인해 데이터가 손실되지만 중요한 경우 Actvity.onSaveInstanceState()
및 Actvity.onRestoreInstanceState()
(또는 이와 유사한)를 사용하여 이미 처리 했어야 합니다.
이것에 대한 당신의 생각을 알려주세요.
건배!
recreate();
언어 변경시 활동을 다시 시작 하는 데 사용할 수 있습니다 .
언어가 변경되면 다음 코드를 사용하여 활동을 다시 시작합니다.
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
Configuration config = getBaseContext().getResources().getConfiguration();
String lang = settings.getString("lang_list", "");
if (! "".equals(lang) && ! config.locale.getLanguage().equals(lang)) {
recreate(); //this is used for recreate activity
Locale locale = new Locale(lang);
Locale.setDefault(locale);
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
}
이 코드로 내 문제를 해결했습니다.
public void setLocale(String lang) {
myLocale = new Locale(lang);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
onConfigurationChanged(conf);
}
@Override
public void onConfigurationChanged(Configuration newConfig)
{
iv.setImageDrawable(getResources().getDrawable(R.drawable.keyboard));
greet.setText(R.string.greet);
textView1.setText(R.string.langselection);
super.onConfigurationChanged(newConfig);
}
이 메서드를 호출하여 앱 로캘을 변경합니다.
public void settingLocale(Context context, String language) {
Locale locale;
Configuration config = new Configuration();
if(language.equals(LANGUAGE_ENGLISH)) {
locale = new Locale("en");
Locale.setDefault(locale);
config.locale = locale;
}else if(language.equals(LANGUAGE_ARABIC)){
locale = new Locale("hi");
Locale.setDefault(locale);
config.locale = locale;
}
context.getResources().updateConfiguration(config, null);
// Here again set the text on view to reflect locale change
// and it will pick resource from new locale
tv1.setText(R.string.one); //tv1 is textview in my activity
}
참고 : 값 및 값 폴더에 문자열을 넣으십시오.
이 접근 방식은 모든 API 수준 장치에서 작동합니다.
attachBaseContext에 대한 기본 활동을 사용하여 로케일 언어를 설정하고 모든 활동에 대해이 활동을 확장하십시오.
open class BaseAppCompactActivity() : AppCompatActivity() { override fun attachBaseContext(newBase: Context) { super.attachBaseContext(LocaleHelper.onAttach(newBase)) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } }
애플리케이션 attachBaseContext
onConfigurationChanged
를 사용하고 로케일 언어 설정public class MyApplication extends Application { private static MyApplication application; @Override public void onCreate() { super.onCreate(); } public static MyApplication getApplication() { return application; } /** * overide to change local sothat language can be chnaged from android device nogaut and above */ @Override protected void attachBaseContext(Context base) { super.attachBaseContext(LocaleHelper.INSTANCE.onAttach(base)); } @Override public void onConfigurationChanged(Configuration newConfig) { setLanguageFromNewConfig(newConfig); super.onConfigurationChanged(newConfig); } /*** also handle chnage language if device language chnaged **/ private void setLanguageFromNewConfig(Configuration newConfig){ Prefs.putSaveLocaleLanguage(this, selectedLocaleLanguage ); LocaleHelper.INSTANCE.onAttach(this); }
Use Locale Helper for handling language changes, this approach work on all device
object LocaleHelper { private var defaultLanguage :String = KycUtility.KYC_LANGUAGE.ENGLISH.languageCode fun onAttach(context: Context, defaultLanguage: String): Context { return setLocale(context, defaultLanguage) } fun setLocale(context: Context, language: String): Context { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { updateResources(context, language) } else updateResourcesLegacy(context, language) } @TargetApi(Build.VERSION_CODES.N) private fun updateResources(context: Context, language: String): Context { val locale = Locale(language) Locale.setDefault(locale) val configuration = context.getResources().getConfiguration() configuration.setLocale(locale) configuration.setLayoutDirection(locale) return context.createConfigurationContext(configuration) } private fun updateResourcesLegacy(context: Context, language: String): Context { val locale = Locale(language) Locale.setDefault(locale) val resources = context.getResources() val configuration = resources.getConfiguration() configuration.locale = locale if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { configuration.setLayoutDirection(locale) } resources.updateConfiguration(configuration, resources.getDisplayMetrics()) return context } }
'developer tip' 카테고리의 다른 글
변경 불가능한 구조체에 대해 공용 읽기 전용 필드를 사용합니까? (0) | 2020.12.11 |
---|---|
존재와 정의의 차이점은 무엇입니까? (0) | 2020.12.11 |
ggplot2에서 로그 색상 스케일을 수행하는 기본 제공 방법이 있습니까? (0) | 2020.12.11 |
FXML 컨트롤러 클래스에 액세스 (0) | 2020.12.11 |
Python ftplib로 FTP를 통해 파일을 다운로드하는 방법 (0) | 2020.12.11 |