1. 程式人生 > >車載定製化系統設定中實現平滑的語言切換

車載定製化系統設定中實現平滑的語言切換

在每個車載系統中,都會有自己獨特的UI風格。比如系統設定這個功能,為了統一風格,我們不能直接去呼叫Android原生的設定應用,而是應該重新做一個風格統一的符合需求的系統設定應用。我們要說的語言切換這個功能,就是其中一個設定項。
如果簡單地實現語言切換,應該是比較簡單的,就是利用反射重新設定一下Locale就好了,這個時候Activity會異常銷燬,並會重新載入重新整理當前語言資源。如下:

	public static void setLanguage(Locale locale){
		try {
			Class c =  Class.forName("com.android.internal.app.LocalePicker");
			Object obj = c.newInstance();
			Method method = c.getMethod("updateLocale", new Class[] {Locale.class});
			method.invoke(obj, locale);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}catch (InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
		}catch (NoSuchMethodException e) {
			e.printStackTrace();
		}catch (IllegalArgumentException | InvocationTargetException e) {
			e.printStackTrace();
		}
	}

但是客戶的需求可沒這麼簡單,首先他不會允許你有一個銷燬再新建立的閃一下的動作,其次會要求增加一個帶loading動畫的彈窗效果。
第一個需求的解決,是在Manifest檔案中對應的設定語言的那個Activity增加屬性: android:configChanges=“locale|layoutDirection”。這樣Activity就不會自動銷燬了。但同時,我們需要註冊一個廣播接收器,監聽語言改變的廣播,在這裡需要把Activity裡面的相關字串重新載入一遍,實現手動的重新整理。如下:

/** 註冊語言改變廣播 */
	private void registerLocalReceiver() {
		IntentFilter mFilter = new IntentFilter();
		mFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
		this.registerReceiver(localReceiver, mFilter);
	}
	
	private BroadcastReceiver localReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context arg0, Intent arg1) {
			Log.i(TAG, "receive the language changed broadcast!");
			initData();
		}
	};
@Override
	public void initData() {
		mTvTitle.setText(getStr(R.string.set_usually));
		mIvTitle.setImageResource(R.drawable.set_usually_n);
		.......
	}

第二個需求,需要在切換語言的同時,還要有一個loading動畫的彈窗效果。如果只是單純地在應用中使用windowManager新增一個view,並利用動畫去轉動,很大概率會出現動畫卡頓的效果,主要是動畫的操作,只能放在主執行緒去做。於是可以把語言切換和動畫的效果,放在另外的程序去處理,這樣就可以實現平滑的語言切換了。彈窗的實現效果如下:

private void showUpdateLanguageDialog(View view){
		try{
			WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
			WindowManager.LayoutParams mWindowParams = new WindowManager.LayoutParams();
			mWindowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
			mWindowParams.format = PixelFormat.TRANSLUCENT;
			mWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
			mWindowParams.x = 0;
			mWindowParams.y = 0;
			mWindowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
					| WindowManager.LayoutParams.FLAG_FULLSCREEN
					| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
			mWindowParams.width = WindowManager.LayoutParams.MATCH_PARENT;
			mWindowParams.height = WindowManager.LayoutParams.MATCH_PARENT;
			mWindowManager.addView(view, mWindowParams);
		}catch(Exception ex){
			
		}
	}

由於Locale是不能通過Parcelable傳遞的,所以使用Configuration來傳遞,切換語言也可以用下面的方式:

IActivityManager iActMag = ActivityManagerNative.getDefault();
		try {
			Configuration config = iActMag.getConfiguration();
			config.locale = locale;
			// 此處需要宣告許可權:android.permission.CHANGE_CONFIGURATION
			// 會重新呼叫 onCreate();
			iActMag.updateConfiguration(config);
		} catch (RemoteException e) {
			e.printStackTrace();
		}