前言
公司項(xiàng)目的Toast統(tǒng)一用到com.blankj.utilcode.util.ToastUtils的工具類,由于公司項(xiàng)目是維護(hù)多語(yǔ)言的,所以在應(yīng)用內(nèi)有切換多語(yǔ)言的入口,但是應(yīng)用切換了多語(yǔ)言后,應(yīng)用的語(yǔ)言已經(jīng)變了,但Toast提示的語(yǔ)言并沒有變,嘗試了用系統(tǒng)的Toast卻是可以改變多語(yǔ)言的,但是項(xiàng)目很多地方用到了ToastUtils工具類,所以不能用系統(tǒng)的Toast來(lái)替換,所以就有了這篇探索文章了。
ToastUtils工具類的探索
這是一個(gè)大神編寫的工具了,這個(gè)工具類的好處就是不用傳入context,可以在很多沒有context對(duì)象的地方調(diào)用,當(dāng)然這個(gè)工具類也對(duì)系統(tǒng)的Toast做了很多的處理,提供了各種功能。具體有什么功能大家可以查看這個(gè)工具類,我們現(xiàn)在回歸到我們的問(wèn)題,ToastUtils切換多語(yǔ)言無(wú)效。
ToastUtils在應(yīng)用中可以很方便的調(diào)用,只需在代碼中寫上ToastUtils.showShort(R.string.bold_text);就可以了。

但是為什么切換多語(yǔ)言就會(huì)沒效呢?
我們從這個(gè)類的源碼來(lái)分析探索一下




從源碼中,我們可以知道ToastUtils不用傳入Context就可以Toast是因?yàn)楣ぞ哳愐呀?jīng)幫我們從反射中拿到了應(yīng)用的Application,所以我們不用傳入Context就可以調(diào)用Toast了,這就是ToastUtils工具類的方便之處。
但是切換多語(yǔ)言時(shí)為什么就不會(huì)切換資源呢?
多語(yǔ)言切換的探索
Android7.0及之后版本,使用了LocaleList,Configuration中的語(yǔ)言設(shè)置可能獲取的不同,而是生效于各自的Context。
* 這會(huì)導(dǎo)致:Android7.0使用舊的方式,有些Activity可能會(huì)顯示為手機(jī)的系統(tǒng)語(yǔ)言。
* Android7.0 優(yōu)化了對(duì)多語(yǔ)言的支持,廢棄了updateConfiguration()方法,替代方法:createConfigurationContext(), 而返回的是Context。
* 也就是語(yǔ)言需要植入到Context中,每個(gè)Context都植入一遍。



我公司的應(yīng)用是兼用到5.0以上的,所以修改多語(yǔ)言就跑到此方法context = context.createConfigurationContext(config);所以重啟activity時(shí)就能更新多語(yǔ)言。但是我們的應(yīng)用是沒有重新啟動(dòng)的,所以Application是沒有更新的。從之前對(duì)ToastUtils的分析,ToastUtils是拿到應(yīng)用的Application當(dāng)做Context的,所以ToastUtils對(duì)于切換多語(yǔ)言就沒效了。從這分析,是Application沒有更新導(dǎo)致多語(yǔ)言沒效,于是就拿系統(tǒng)的Toast傳入application當(dāng)Context嘗試,果真也是無(wú)效的。
解決辦法
一.既然是Application沒有更新導(dǎo)致多語(yǔ)言無(wú)效,那我們就更新Application就可以了。但Application是應(yīng)用一啟動(dòng)就創(chuàng)建了,自始至終就是這個(gè),不會(huì)更新的,所以我們就得重啟應(yīng)用,殺掉這個(gè)進(jìn)程來(lái)更新這個(gè)Application。
1.?
Intent intent = new Intent(this, Object.class);
startActivity(intent);
System.exit(0);
finish();
2. 通過(guò)ActivityManager來(lái)重新啟動(dòng)應(yīng)用程序:
ActivityManager manager = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
manager.restartPackage("com.example.test");
3. 通過(guò)flag來(lái)實(shí)現(xiàn):
private void restartApplication() {
??????? final Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
??????? intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
??????? startActivity(intent);
}
4. 利用PendingIntent
Intent mStartActivity = new Intent(context, StartActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(context, mPendingIntentId,??? mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);
只有關(guān)閉進(jìn)程才算真正的更新了Application,所以只有1.4是有效的,但是這個(gè)更新Application的方式體驗(yàn)很不好,因?yàn)殛P(guān)閉進(jìn)程到重啟會(huì)出現(xiàn)黑屏。
二.從多語(yǔ)言的切換我們知道,切換多語(yǔ)言有兩種方法
1.context = context.createConfigurationContext(config);
2.resources.updateConfiguration(config, dm);
第二種方法Android7.0 優(yōu)化了對(duì)多語(yǔ)言的支持,廢棄了updateConfiguration()方法,替代方法:createConfigurationContext(), 而返回的是Context。也就是語(yǔ)言需要植入到Context中,每個(gè)Context都植入一遍。使用第二種方法會(huì)導(dǎo)致:Android7.0使用舊的方式,有些Activity可能會(huì)顯示為手機(jī)的系統(tǒng)語(yǔ)言。
但是我們可以在更新多語(yǔ)言的時(shí)候把應(yīng)用的application傳進(jìn)來(lái)更新應(yīng)用的application資源就可以了,而不需要替換application

ToastUtils切換多語(yǔ)言就可以了,應(yīng)用的Application也更新了資源。這種方法效果比一的方法好,對(duì)應(yīng)用沒有什么影響。
總結(jié)
經(jīng)過(guò)這次的bug的處理,讓我對(duì)源碼的學(xué)習(xí)更加深入,學(xué)會(huì)如何分析問(wèn)題,找到問(wèn)題和解決問(wèn)題。其中也學(xué)習(xí)了多語(yǔ)言的切換的,反射,應(yīng)用重啟還有各個(gè)Context的不同,雖然理解的可能還不是很深入,但是萬(wàn)丈高樓平地起,凡是都是從點(diǎn)滴積累的,以后繼續(xù)加油!