不只是切换多语言Android
Posted vv_小虫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不只是切换多语言Android相关的知识,希望对你有一定的参考价值。
接着前面的内容往下走不只是切换多语言Android(一),我们来实现一下android app内切换语言。
思路一:
1、把所有的activity用一个集合装起来
2、改变app的语言环境
3、干掉所有的activity,然后进入重新启动app
思路二:
1、获取所有需要改变语言的组件
2、改变app的语言环境
3、通知所有的组件重新加载text
两种方式比较,如果跟偏重程序性能的话,用第一种方案(微信毛貌似用的就是这种),如果偏重用户体验不重启app的话,就用第二种方案。
在此之前呢,我们先了解下观察者模式,不了解没关系,我们通过案例说明一下~~
1、(被观察的事物)我们这里的被观察的对象就是修改语言了,于是我们把修改语言这个subject抽取出来:
LanguageSubject.java
public abstract class LanguageSubject
private List<LanguageObserver> observers;
public synchronized void attach(LanguageObserver observer)
if (observers == null)
observers = new ArrayList<>();
observers.add(observer);
public synchronized void dettach(LanguageObserver observer)
if (observers == null || observers.size() == 0 || !observers.contains(observer)) return;
observers.remove(observer);
protected void notifyChangeLanguage(String language) throws Exception
if (observers == null || observers.size() == 0) return;
for (LanguageObserver observer :
observers)
observer.update(language);
public interface IChangeSuccessCallBack
void success();
void erro();
里面方法定义很简单,包括:attach(添加需要通知的对象)、dettach(移除通知对象)、notifyChangeLanguage(通知所有的对象“我需要修改语言了“)。
2、(需要通知的对象LanguageObserver)
/**
* Created by leo on 17/4/6.
*/
public interface LanguageObserver
void update(String language) throws Exception;
当接到通知的时候,需要做出相应的动作,update方法即为做出的响应。
3、说说我们具体的主题事件类了(修改语言)
package com.yasin.library;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.DisplayMetrics;
import android.util.Log;
import com.yasin.library.util.LANGUAGE;
import com.yasin.library.util.LanguageSpUtil;
import java.util.Locale;
/**
* Created by leo on 17/4/6.
*/
public class LanguageManage extends LanguageSubject
private static final String TAG = "LanguageManage";
private static LanguageManage instance;
private Context context;
private LanguageManage(Context context)
this.context = context;
public static synchronized LanguageManage getInstance(Context context)
if (instance == null)
instance = new LanguageManage(context);
return instance;
public void change(LANGUAGE language, IChangeSuccessCallBack callBack)
try
// 应用用户选择语言
if (language == LANGUAGE.ZH)
change(language, Locale.CHINESE);
if(callBack!=null)callBack.success();
else if (language == LANGUAGE.EN)
change(language, Locale.ENGLISH);
if(callBack!=null)callBack.success();
else
if (callBack != null) callBack.erro();
Log.e(TAG, "Language: " + language.toString() + " is not supported!");
catch (Exception e)
e.printStackTrace();
if (callBack != null) callBack.erro();
private void change(LANGUAGE language, Locale locale) throws Exception
Resources resources = context.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
Configuration config = resources.getConfiguration();
config.locale = locale;
resources.updateConfiguration(config, dm);
notifyChangeLanguage(language.toString());
LanguageSpUtil.saveLanguage(context, language);
LanguageManage是继承了LanguageSubject主题。
好啦~观察者模式就完啦~! 是不是觉得很简单呢?
我们也跟AppCompatActivity一样,创建一个LanguageDelegate(为我们的观察者跟inflator 的factory)需要实现LanguageObserver跟LayoutInflaterFactory:
package com.yasin.library;
import android.app.Activity;
import android.content.Context;
import android.support.v4.view.LayoutInflaterFactory;
/**
* Created by leo on 17/4/6.
*/
public abstract class LanguageDelegate implements LanguageObserver, LayoutInflaterFactory
protected Context mContext;
public static LanguageDelegate create(Activity activity)
return new LanguageDelegateBaseImp(activity);
public abstract void installViewFactory();
public void onResume()
if(mContext==null)return;
LanguageManage.getInstance(mContext).attach(this);
public void onDestory()
if(mContext==null)return;
LanguageManage.getInstance(mContext).dettach(this);
在onResume方法的时候,把我们的观察者对象装进主题事件中:
public void onResume()
if(mContext==null)return;
LanguageManage.getInstance(mContext).attach(this);
然后在onDestory的时候把我们的观察者对象移除被观察者事物:
public void onDestory()
if(mContext==null)return;
LanguageManage.getInstance(mContext).dettach(this);
LanguageDelegateBaseImp具体的观察者对象(具体实现我们切换语言):
package com.yasin.library;
import android.content.Context;
import android.support.v4.view.LayoutInflaterCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import com.yasin.library.exception.LanguageException;
import com.yasin.library.widge.LanguageButton;
import com.yasin.library.widge.LanguageEditText;
import com.yasin.library.widge.LanguageSupportable;
import com.yasin.library.widge.LanguageTextView;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
/**
* Created by leo on 17/4/6.
*/
public class LanguageDelegateBaseImp extends LanguageDelegate
private static final String TAG = "LanguageDelegateBaseImp";
private List<WeakReference<LanguageSupportable>> mSupports;
public LanguageDelegateBaseImp(Context context)
this.mContext = context;
mSupports = new ArrayList<>();
@Override
public void installViewFactory()
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
if (layoutInflater.getFactory() == null)
LayoutInflaterCompat.setFactory(layoutInflater, this);
else
if (!(LayoutInflaterCompat.getFactory(layoutInflater)
instanceof LanguageDelegateBaseImp))
Log.i(TAG, "The Activity's LayoutInflater already has a Factory installed"
+ " so we can not install LanguageCompat's");
@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs)
if ("TextView".equals(name))
LanguageTextView supportable = new LanguageTextView(context, attrs);
mSupports.add(new WeakReference<LanguageSupportable>(supportable));
return supportable;
else if ("Button".equals(name))
LanguageButton supportable = new LanguageButton(context, attrs);
mSupports.add(new WeakReference<LanguageSupportable>(supportable));
return supportable;
else if ("EditText".equals(name))
LanguageEditText supportable = new LanguageEditText(context, attrs);
mSupports.add(new WeakReference<LanguageSupportable>(supportable));
return supportable;
return null;
@Override
public void update(String language) throws Exception
try
for (WeakReference<LanguageSupportable> support : mSupports)
LanguageSupportable s = support.get();
s.change();
catch (Exception e)
throw new LanguageException(e.getMessage(), e.getCause());
在具体的观察者对象LanguageDelegateBaseImp中,当我们的infaltor.inflate的时候(加载xml文件),就会根据组件的名字创建对应的组件:
package com.yasin.library.widge;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
import com.yasin.library.helper.TextSupportHelper;
import com.yasin.library.helper.TextSupportHelperImp;
/**
* Created by leo on 17/4/6.
*/
public class LanguageTextView extends TextView implements LanguageSupportable
private TextSupportHelper textSupportHelper;
public LanguageTextView(Context context, AttributeSet attrs)
super(context, attrs);
initViews(attrs, 0);
public LanguageTextView(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
initViews(attrs, defStyleAttr);
private void initViews(AttributeSet attrs, int defStyleAttr)
textSupportHelper = new TextSupportHelperImp(this, attrs, defStyleAttr);
@Override
public void change()
textSupportHelper.apply();
比如TextView,然后当textSupportHelper帮我们实现切换text文字:
package com.yasin.library.helper;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.TextView;
import com.yasin.library.R;
/**
* Created by leo on 17/4/7.
*/
public class TextSupportHelperImp extends TextSupportHelper
/**
* TextView的string的资源id
*/
protected int resourceId;
/**
* 当前的TextView
*/
protected TextView textView;
public int getResourceId()
return resourceId;
public void setResourceId(int resourceId)
this.resourceId = resourceId;
public TextSupportHelperImp(TextView textView, AttributeSet attrs, int defStyleAttr)
this.textView = textView;
//获取自定义属性
// <?xml version="1.0" encoding="utf-8"?>
// <resources>
// <declare-styleable name="LanguageHelper">
// <attr name="android:text" />
// <attr name="android:hint" />
// </declare-styleable>
// </resources
TypedArray a = textView.getContext().obtainStyledAttributes(attrs, R.styleable.LanguageHelper, defStyleAttr, 0);
try
//获取到text的资源路径
resourceId = a.getResourceId(R.styleable.LanguageHelper_android_text, 0);
catch (Exception e)
finally
a.recycle();
@Override
public void apply()
//判断当前资源路径是否有效
//因为我们在xml中可能是直接设置的文字,就无法国际化了
int id = checkResourceId(resourceId);
if (id != INVALID_ID)
try
textView.setText(textView.getContext().getResources().getString(id));
catch (Exception e)
好啦!!差不多定义完了,怎么用呢??
首先创建两个value文件夹(我这里就是英文跟中文),然后里面放对应的string文件:
values-en:
<resources>
<string name="app_name">LanguageSupport</string>
<string name="hello">Hello LanguageSupport!</string>
<string name="switch_language">switch language</string>
<string name="change_succ">change success!</string>
</resources>
values-zh:
<resources>
<string name="app_name">语言切换</string>
<string name="hello">你好 !</string>
<string name="switch_language">切换语言</string>
<string name="change_succ">修改成功!</string>
</resources>
跟AppCompatActivity一样,创建一个BaseActivity:
package com.yasin.languagesupport;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.view.LayoutInflaterCompat;
import android.support.v4.view.LayoutInflaterFactory;
import android.support.v7.app.AppCompatActivity;
import com.yasin.library.LanguageDelegate;
/**
* Created by leo on 17/4/6.
*/
public class BaseActivity extends AppCompatActivity
private LanguageDelegate mDelegate;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
LayoutInflaterCompat.setFactory(getLayoutInflater(),getLanguageDelegate());
super.onCreate(savedInstanceState);
ActivityManager.addActivity(this);
private LayoutInflaterFactory getLanguageDelegate()
return mDelegate=LanguageDelegate.create(this);
@Override
protected void onResume()
super.onResume();
mDelegate.onResume();
@Override
protected void onDestroy()
super.onDestroy();
mDelegate.onDestory();
ActivityManager.remove(this);
然后就可以用了:
package com.yasin.languagesupport;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Toast;
import com.yasin.library.LanguageManage;
import com.yasin.library.LanguageSubject;
import com.yasin.library.util.LANGUAGE;
import com.yasin.library.util.LanguageSpUtil;
public class MainActivity extends BaseActivity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setTitle(R.string.app_name);
setContentView(R.layout.activity_main);
public void change(View view)
String language = LanguageSpUtil.getLanguage(this);
LANGUAGE lan;
if(TextUtils.isEmpty(language))
language= LANGUAGE.ZH.toString();
if(LANGUAGE.EN.toString().equals(language))
lan=LANGUAGE.ZH;
else
lan=LANGUAGE.EN;
LanguageManage.getInstance(this).change(lan, new LanguageSubject.IChangeSuccessCallBack()
@Override
public void success()
Toast.makeText(getApplicationContext(),getString(R.string.change_succ),Toast.LENGTH_SHORT).show();
setTitle(R.string.app_name);
// startActivity(new Intent(MainActivity.this,SecondActivity.class));
@Override
public void erro()
);
好啦~~还是不懂的童鞋可以直接拖代码运行一下应该就会明白了,不懂的也可以找我哈!!
最后附上项目github的链接:
https://github.com/913453448/LanguageSupport
以上是关于不只是切换多语言Android的主要内容,如果未能解决你的问题,请参考以下文章