+7

Thay đổi Ngôn ngữ không cần restart activity trên android ?

Chào các bạn hôm nay mình xin phép viết một bài về cách refesh lại text khi thay đổi ngôn ngữ mà không cần phải refesh activity. Hôm nay mình xin được viết về 3 cách để thay đổi ngôn ngữ (ý mình là thay đổi ngôn ngữ ngay tại cái màn hình có chứa cài đặt thay đổi ngôn ngữ nhé),mình sẽ chỉ ra ưu điểm và nhược điểm của 3 cách trên và nếu bạn không có thời gian đọc thì bạn có thể đi đến cách 3 nhé vì cách này do quá trình mình học hỏi và nghiên cứu nên mình thấy rất hay. Thôi chúng ta bắt đầu vào từng cách 1. Ở đây sẽ tạo 1 project demo sẽ tạo 1 layout đăng nhập, việc tạo ra 2 file string locale nếu bạn nào k biết có thể đọc tai đây. hôm nay mình chỉ ví dụ về 3 cách thay đổi ngôn ngữ thôi nhé. đây là code Main Activity

// main Activity
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    TextView mTextLogin,mTextUsername,mTextPassword,mTextForotPassword;
    Button mButtonLogin,mButtonRegister,mButtonVietnamese,mButtonEnglish;
    EditText mEditUsername,mEditPassword;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initview();
    }
    private void refeshLayout(){
        Intent intent = getIntent();
        overridePendingTransition(0, 0);
        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        finish();
        overridePendingTransition(0, 0);
        startActivity(intent);
    }
    public void initview(){
        mTextLogin=(TextView) findViewById(R.id.text_title_login);
        mTextUsername=(TextView) findViewById(R.id.text_username);
        mTextPassword=(TextView) findViewById(R.id.text_password);
        mTextForotPassword=(TextView) findViewById(R.id.text_forgot_password);
        mButtonLogin=(Button) findViewById(R.id.button_login);
        mButtonRegister=(Button)findViewById(R.id.button_register);
        mButtonVietnamese=(Button) findViewById(R.id.button_vietnamese);
        mButtonEnglish=(Button) findViewById(R.id.button_english);
        mEditUsername=(EditText) findViewById(R.id.edit_username);
        mEditPassword=(EditText) findViewById(R.id.edit_password);
        mButtonEnglish.setOnClickListener(this);
        mButtonVietnamese.setOnClickListener(this);

    }
    public void refeshText(){
        mTextLogin.setText(getResources().getString(R.string.text_login));
        mTextUsername.setText(getResources().getString(R.string.text_username));
        mTextPassword.setText(getResources().getString(R.string.text_password));
        mTextForotPassword.setText(getResources().getString(R.string.text_forgetpassword));
        mButtonLogin.setText(getResources().getString(R.string.text_login));
        mButtonRegister.setText(getResources().getString(R.string.text_resgister));
        mButtonVietnamese.setText(getResources().getString(R.string.text_vietnamese));
        mButtonEnglish.setText(getResources().getString(R.string.text_english));
        mEditUsername.setHint(getResources().getString(R.string.text_username));
        mEditPassword.setHint(getResources().getString(R.string.text_password));

    }
    public static void setLocale(String lang, Resources resources) {
        Locale myLocale = new Locale(lang);
        DisplayMetrics dm = resources.getDisplayMetrics();
        Configuration conf = resources.getConfiguration();
        conf.locale = myLocale;
        resources.updateConfiguration(conf, dm);
    }
    private void refreshResource(ViewGroup viewGroup) {
        int count = viewGroup.getChildCount();
        for (int i = 0; i < count; i++) {
            View view = viewGroup.getChildAt(i);
            if (view instanceof ViewGroup)
                refreshResource((ViewGroup) view);
            else {
                if(view.getTag()==null){
                    continue;
                }
                int resId = getResources().getIdentifier(view.getTag().toString(), "string", getPackageName());
                if(view instanceof EditText){
                    EditText editText=(EditText)view;
                    editText.setHint(getString(resId));

                }else if(view instanceof TextView){
                    TextView textView=(TextView) view;
                    textView.setText(getString(resId));
                }else if(view instanceof Button){
                    Button button=(Button) view;
                    button.setText(getString(resId));
                }
            }
        }
    }

    @Override
    public void onClick(View view) {
        View rootView = getWindow().getDecorView().getRootView();
        switch (view.getId()){
            case R.id.button_english:
                setLocale("en",getResources());
                refeshLayout();
               // refeshText();
              //  refreshResource((ViewGroup) rootView);
                break;
            default:
                setLocale("ja",getResources());
                refeshLayout();
               // refeshText();
                //refreshResource((ViewGroup) rootView);
                break;
        }
    }
}

Cách 1: refesh activity

  • đoạn code sử dụng
 private void refeshLayout(){
        Intent intent = getIntent();
        overridePendingTransition(0, 0);
        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        finish();
        overridePendingTransition(0, 0);
        startActivity(intent);
    }
  • video demo:
  • Ưu điểm: ở cách này là chúng ta không phải viết quá nhiều code vào việc thay đổi text. bạn chỉ cần refesh lại chính cái acitivity bằng cách finish nó và start lại activity.
  • Nhược điểm: vì là finish và start lại nên khả năng mất dữ liệu sẽ xảy ra. bạn có thể nhìn vào video khi tôi đang nhập dữ liệu vào 2 ô editText và tôi tiến hành chuyển đổi ngôn ngữ thì những text tôi nhập sẽ bị mất đi.

cách 2: set lại text cho các view bằng cách setText như một người thợ thủ công

  • đoạn code sử dụng
 public void refeshText(){
        mTextLogin.setText(getResources().getString(R.string.text_login));
        mTextUsername.setText(getResources().getString(R.string.text_username));
        mTextPassword.setText(getResources().getString(R.string.text_password));
        mTextForotPassword.setText(getResources().getString(R.string.text_forgetpassword));
        mButtonLogin.setText(getResources().getString(R.string.text_login));
        mButtonRegister.setText(getResources().getString(R.string.text_resgister));
        mButtonVietnamese.setText(getResources().getString(R.string.text_vietnamese));
        mButtonEnglish.setText(getResources().getString(R.string.text_english));
        mEditUsername.setHint(getResources().getString(R.string.text_username));
        mEditPassword.setHint(getResources().getString(R.string.text_password))
    }

-video demo:

  • ưu điểm : những text đã nhập vào 2 ô edittext sẽ không bị mất vì bạn chỉ thực hiện set lại text cho các view chứ k hề finish rồi start lại activity như ở cách đầu tiên.
  • nhược điểm: nhưng chúng ta lại phải set lại text cho rất nhiều TextView và EditText. tôi đặt trường hợp khi bạn có yêu cầu làm 1 màn hình mà bên trong có chứa đến 20 đến 30 cái TextView như trong dự án tôi đang làm thì việc mà bạn dành thời gian để fđặt id cho từng view và findViewbyid cho nó cũng mất khá nhiều thời gian của bạn, còn chưa kể bạn có thể bị nhầm lẫn giữa các view.
 public void initview(){
        mTextLogin=(TextView) findViewById(R.id.text_title_login);
        mTextUsername=(TextView) findViewById(R.id.text_username);
        mTextPassword=(TextView) findViewById(R.id.text_password);
        mTextForotPassword=(TextView) findViewById(R.id.text_forgot_password);
        mButtonLogin=(Button) findViewById(R.id.button_login);
        mButtonRegister=(Button)findViewById(R.id.button_register);
        mButtonVietnamese=(Button) findViewById(R.id.button_vietnamese);
        mButtonEnglish=(Button) findViewById(R.id.button_english);
        mEditUsername=(EditText) findViewById(R.id.edit_username);
        mEditPassword=(EditText) findViewById(R.id.edit_password);
    }
  • rất may là có rất nhiều thư viện có thể hỗ trợ bạn findViewById ví dụ như databinding hay butterkinfe. nhưng nếu sử dụng chúng thì bạn vẫn phải set lại text cho các view chỉ khác là bạn không phải mất thời gian để tự findViewById cho cừng đấy cái view, nên cách này mình thấy cũng không khả thi cho lắm(cách này chỉ dành cho những con ong chăm chỉ và những người thợ cần mẫn 😄 ).

cách 3: gán thẻ tag trong layout (xml) và sử dụng getIdentifier để tìm và set lại text cho View

  • đoạn code sử dụng trong file java.
 private void refreshResource(ViewGroup viewGroup) {
        int count = viewGroup.getChildCount();
        for (int i = 0; i < count; i++) {
            View view = viewGroup.getChildAt(i);
            if (view instanceof ViewGroup)
                refreshResource((ViewGroup) view);
            else {
                if(view.getTag()==null){
                    continue;
                }
                int resId = getResources().getIdentifier(view.getTag().toString(), "string", getPackageName());
                if(view instanceof EditText){
                    EditText editText=(EditText)view;
                    editText.setHint(getString(resId));

                }else if(view instanceof TextView){
                    TextView textView=(TextView) view;
                    textView.setText(getString(resId));
                }else if(view instanceof Button){
                    Button button=(Button) view;
                    button.setText(getString(resId));
                }
            }
        }
    }
  • Đoạn code sử dụng tag trên xml
 android:text="@string/text_login"
 android:tag="text_login"
  • video demo:
  • giả thích code: ở method trên mình chỉ cần truyền viewGroup vào sẽ get tất cả các view con trong activity ,getTag, dựa vào tag và sẽ tìm ra Resources Id.
 int resId = getResources().getIdentifier(view.getTag().toString(), "string", getPackageName());
  • ưu điểm: bạn không cần phải findViewById mà vẫn có thể set lại text cho tất cả các View trong ViewGroup, và quan trong những data mà bạn nhập vào các EditText sẽ không bị mất, bạn cũng sẽ chẳng phải đau đầu để nghĩ ra cách đặt id cho từng view một, nó cũng tránh việc bạn phải findViewById cho nhưng TextView mà bạn sẽ chẳng dùng đến nó trong code java.
  • Nhược điểm: bạn đầu mình nghĩ nó sẽ ảnh hưởng đến performance vì phải for từng view con nhưng hiện tại code bên trong dự án của mình thì vẫn ổn vì một màn hình mình đang sử dụng tới gần 60 EditText và Textview mà nó vẫn sống khỏe 😄.

4 chốt.

Cảm ơn các bạn vì đã đọc bài. nếu có cách nào hay thì có thể chia sẻ với mình và mọi người.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí