ภาพรวม
ตัวอย่างนี้สาธิตการเปลี่ยนภาษาแอปพลิเคชัน (Locale) แบบไดนามิกเมื่อผู้ใช้เลือกจาก Spinner โดยใช้ Configuration และ Resources แล้ว Recreate Activity
ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่
Android Studio → File → New Project → Empty Activity
ขั้นตอนที่ 2: สร้าง String Resources สำหรับแต่ละภาษา
res/values/strings.xml (Default - English)
<resources>
<string name="app_name">Language Demo</string>
<string name="thank_you">Thank you</string>
<string name="select_language">Select Language</string>
</resources>
res/values-th/strings.xml (Thai)
<resources>
<string name="app_name">สาธิตภาษา</string>
<string name="thank_you">ขอบคุณ</string>
<string name="select_language">เลือกภาษา</string>
</resources>
res/values-es/strings.xml (Spanish)
<resources>
<string name="app_name">Demo de Idioma</string>
<string name="thank_you">Gracias</string>
<string name="select_language">Seleccionar Idioma</string>
</resources>
res/values-fr/strings.xml (French)
<resources>
<string name="app_name">Démo de Langue</string>
<string name="thank_you">Merci</string>
<string name="select_language">Sélectionner la langue</string>
</resources>
res/values-hi/strings.xml (Hindi)
<resources>
<string name="app_name">भाषा डेमो</string>
<string name="thank_you">धन्यवाद</string>
<string name="select_language">भाषा चुनें</string>
</resources>
ขั้นตอนที่ 3: จัดรูปแบบหน้าจอ (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<Spinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/spinner"
android:layout_centerHorizontal="true"
android:layout_marginTop="32dp"
android:text="@string/thank_you"
android:textSize="24sp"
android:textStyle="bold" />
</RelativeLayout>
ขั้นตอนที่ 4: เขียนโค้ด MainActivity.java
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
private Spinner spinner;
private TextView textView;
private String currentLanguage = "en";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// โหลดภาษาที่บันทึกไว้ (จาก SharedPreferences)
loadSavedLocale();
spinner = findViewById(R.id.spinner);
textView = findViewById(R.id.textView);
// รายการภาษา
List languages = new ArrayList<>();
languages.add(getString(R.string.select_language));
languages.add("English");
languages.add("Español");
languages.add("Français");
languages.add("ไทย");
languages.add("हिन्दी");
ArrayAdapter adapter = new ArrayAdapter<>(
this, android.R.layout.simple_spinner_item, languages);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
// ตั้งค่า Selection ให้ตรงกับภาษาปัจจุบัน
setSpinnerSelection();
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
if (position == 0) return; // "Select Language" placeholder
String localeCode;
switch (position) {
case 1: localeCode = "en"; break;
case 2: localeCode = "es"; break;
case 3: localeCode = "fr"; break;
case 4: localeCode = "th"; break;
case 5: localeCode = "hi"; break;
default: return;
}
if (!localeCode.equals(currentLanguage)) {
setLocale(localeCode);
} else {
Toast.makeText(MainActivity.this, "Language already selected", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onNothingSelected(AdapterView> parent) {}
});
}
private void loadSavedLocale() {
// อ่านจาก SharedPreferences (ควรทำใน Application Class หรือ BaseActivity)
// ตัวอย่างง่ายๆ:
currentLanguage = getSharedPreferences("settings", MODE_PRIVATE)
.getString("locale", "en");
}
private void saveLocale(String localeCode) {
getSharedPreferences("settings", MODE_PRIVATE)
.edit().putString("locale", localeCode).apply();
}
private void setSpinnerSelection() {
switch (currentLanguage) {
case "en": spinner.setSelection(1); break;
case "es": spinner.setSelection(2); break;
case "fr": spinner.setSelection(3); break;
case "th": spinner.setSelection(4); break;
case "hi": spinner.setSelection(5); break;
}
}
private void setLocale(String localeCode) {
Locale locale = new Locale(localeCode);
Locale.setDefault(locale);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
conf.setLocale(locale);
} else {
conf.locale = locale;
}
res.updateConfiguration(conf, dm);
// บันทึกภาษาที่เลือก
saveLocale(localeCode);
// Restart Activity เพื่อโหลด Resource ใหม่
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
}
@Override
public void onBackPressed() {
// ออกจากแอปโดยไม่เก็บใน Back Stack
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
}
ขั้นตอนที่ 5: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.com.sample">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:configChanges="locale|layoutDirection">
<intent-filter>
</intent-filter>
</activity>
</application>
</manifest>
💡 android:configChanges="locale|layoutDirection"
เพิ่มบรรทัดนี้ใน Activity เพื่อป้องกัน Recreation อัตโนมัติเมื่อ Locale เปลี่ยน (เราจัดการเองใน setLocale)
การทดสอบ
รันแอป → เลือกภาษาจาก Spinner → แอปจะ Restart และแสดงภาษาใหม่ทันที
แนวทางปัจจุบัน: AppCompatDelegate (Support Library)
ใช้ AppCompatDelegate.setApplicationLocales() (API 33+ / AppCompat 1.6+) ซึ่งจัดการทุกอย่างให้อัตโนมัติ:
// build.gradle
implementation "androidx.appcompat:appcompat:1.6.1"
// ใน Application Class หรือ Activity
import androidx.appcompat.app.AppCompatDelegate;
import android.os.LocaleListCompat;
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// โหลดภาษาที่บันทึกไว้ตอนเริ่มแอป
String savedLocale = getSharedPreferences("settings", MODE_PRIVATE)
.getString("locale", "en");
setAppLocale(savedLocale);
}
public static void setAppLocale(String localeCode) {
LocaleListCompat locales = LocaleListCompat.forLanguageTags(localeCode);
AppCompatDelegate.setApplicationLocales(locales);
}
}
// เรียกใช้จาก Activity
MyApplication.setAppLocale("th"); // ไม่ต้อง Restart Activity!
Best Practices
- เก็บ Locale ใน SharedPreferences หรือ DataStore
- ตั้งค่า Locale ใน Application.onCreate() ก่อน Activity ใดๆ ทำงาน
- ใช้
android:configChanges="locale|layoutDirection"ป้องกัน Recreate ซ้ำ - ทดสอบ RTL Languages (Arabic, Hebrew) ด้วย
layoutDirection - แยก String Resources ตามภาษาอย่างเคร่งครัด (อย่า Hardcode String ในโค้ด)