免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
android源碼分析(一)

android語言切換是在packages/apps/Settings/com/android/settings/LocalePicker.java的updateLocale()函數(shù)中調(diào)用.

  1. /** 
  2.      * Requests the system to update the system locale. Note that the system looks halted 
  3.      * for a while during the Locale migration, so the caller need to take care of it. 
  4.      */  
  5.     public static void updateLocale(Locale locale) {  
  6.         try {  
  7.             IActivityManager am = ActivityManagerNative.getDefault();  
  8.             Configuration config = am.getConfiguration();  
  9.   
  10.             config.locale = locale;  
  11.   
  12.             // indicate this isn't some passing default - the user wants this remembered  
  13.             config.userSetLocale = true;  
  14.   
  15.             am.updateConfiguration(config);  
  16.             // Trigger the dirty bit for the Settings Provider.  
  17.             BackupManager.dataChanged("com.android.providers.settings");  
  18.         } catch (RemoteException e) {  
  19.             // Intentionally left blank  
  20.         }  
  21.     }  
 從注釋可以看出, 只要本地local改變就會調(diào)用該函數(shù). 查看ActivityManagerNative的getDefault()可以看到, 該函數(shù)返回的是遠程服務對象ActivityManagerServices.java在本地的一個代理.  最終調(diào)用的是ActivityManagerService.java中的updateConfiguration()函數(shù). 

  1. public void updateConfiguration(Configuration values) {  
  2.         enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,  
  3.                 "updateConfiguration()");  
  4.   
  5.         synchronized(this) {  
  6.             if (values == null && mWindowManager != null) {  
  7.                 // sentinel: fetch the current configuration from the window manager  
  8.                 values = mWindowManager.computeNewConfiguration();  
  9.             }  
  10.   
  11.             if (mWindowManager != null) {  
  12.                 mProcessList.applyDisplaySize(mWindowManager);  
  13.             }  
  14.   
  15.             final long origId = Binder.clearCallingIdentity();  
  16.             if (values != null) {  
  17.                 Settings.System.clearConfiguration(values);  
  18.             }  
  19.             updateConfigurationLocked(values, nullfalsefalse);  
  20.             Binder.restoreCallingIdentity(origId);  
  21.         }  
  22.     }  
 該函數(shù), 首先進行的是權(quán)限的校驗. 然后調(diào)用updateConfigurationLocked()函數(shù). 

 

  1. /** 
  2.      * Do either or both things: (1) change the current configuration, and (2) 
  3.      * make sure the given activity is running with the (now) current 
  4.      * configuration.  Returns true if the activity has been left running, or 
  5.      * false if <var>starting</var> is being destroyed to match the new 
  6.      * configuration. 
  7.      * @param persistent TODO 
  8.      */  
  9.     public boolean updateConfigurationLocked(Configuration values,  
  10.             ActivityRecord starting, boolean persistent, boolean initLocale) {  
  11.         int changes = 0;  
  12.           
  13.         boolean kept = true;  
  14.           
  15.         if (values != null) {  
  16.             Configuration newConfig = new Configuration(mConfiguration);  
  17.             changes = newConfig.updateFrom(values);  
  18.             if (changes != 0) {  
  19.                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {  
  20.                     Slog.i(TAG, "Updating configuration to: " + values);  
  21.                 }  
  22.                   
  23.                 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);  
  24.   
  25.                 if (values.locale != null && !initLocale) {  
  26.                     saveLocaleLocked(values.locale,   
  27.                                      !values.locale.equals(mConfiguration.locale),  
  28.                                      values.userSetLocale, values.simSetLocale);  
  29.                 }  
  30.   
  31.                   
  32.                 mConfigurationSeq++;  
  33.                 if (mConfigurationSeq <= 0) {  
  34.                     mConfigurationSeq = 1;  
  35.                 }  
  36.                 newConfig.seq = mConfigurationSeq;  
  37.                 mConfiguration = newConfig;  
  38.                 Slog.i(TAG, "Config changed: " + newConfig);  
  39.   
  40.                 final Configuration configCopy = new Configuration(mConfiguration);  
  41.   
  42.                 AttributeCache ac = AttributeCache.instance();  
  43.                 if (ac != null) {  
  44.                     ac.updateConfiguration(configCopy);  
  45.                 }  
  46.   
  47.                 // Make sure all resources in our process are updated  
  48.                 // right now, so that anyone who is going to retrieve  
  49.                 // resource values after we return will be sure to get  
  50.                 // the new ones.  This is especially important during  
  51.                 // boot, where the first config change needs to guarantee  
  52.                 // all resources have that config before following boot  
  53.                 // code is executed.  
  54.                 mSystemThread.applyConfigurationToResources(configCopy);  
  55.   
  56.                 if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {  
  57.                     Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);  
  58.                     msg.obj = new Configuration(configCopy);  
  59.                     mHandler.sendMessage(msg);  
  60.                 }  
  61.           
  62.                 for (int i=mLruProcesses.size()-1; i>=0; i--) {  
  63.                     ProcessRecord app = mLruProcesses.get(i);  
  64.                     try {  
  65.                         if (app.thread != null) {  
  66.                             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "  
  67.                                     + app.processName + " new config " + mConfiguration);  
  68.                             app.thread.scheduleConfigurationChanged(configCopy);  
  69.                         }  
  70.                     } catch (Exception e) {  
  71.                     }  
  72.                 }  
  73.                 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);  
  74.                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY  
  75.                         | Intent.FLAG_RECEIVER_REPLACE_PENDING);  
  76.                 broadcastIntentLocked(nullnull, intent, nullnull0nullnull,  
  77.                         nullfalsefalse, MY_PID, Process.SYSTEM_UID);  
  78.                 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {  
  79.                     broadcastIntentLocked(nullnull,  
  80.                             new Intent(Intent.ACTION_LOCALE_CHANGED),  
  81.                             nullnull0nullnull,  
  82.                             nullfalsefalse, MY_PID, Process.SYSTEM_UID);  
  83.                 }  
  84.                   
  85.             }  
  86.         }  
  87.           
  88.         if (changes != 0 && starting == null) {  
  89.             // If the configuration changed, and the caller is not already  
  90.             // in the process of starting an activity, then find the top  
  91.             // activity to check if its configuration needs to change.  
  92.             starting = mMainStack.topRunningActivityLocked(null);  
  93.         }  
  94.           
  95.         if (starting != null) {  
  96.             kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);  
  97.             // And we need to make sure at this point that all other activities  
  98.             // are made visible with the correct configuration.  
  99.             mMainStack.ensureActivitiesVisibleLocked(starting, changes);  
  100.         }  
  101.           
  102.         if (values != null && mWindowManager != null) {  
  103.             mWindowManager.setNewConfiguration(mConfiguration);  
  104.         }  
  105.           
  106.         return kept;  
  107.     }  

整個語言切換就在這個函數(shù)中完成. 咋一看似乎沒感覺到該函數(shù)做了哪些事情. 我們首先來看注釋: Do either or both things: (1) change the current configuration, and (2)
 make sure the given activity is running with the (now) current. configuration大概意思是: 這個函數(shù)做了兩件事情. (1). 改變當前的configuration. 意思就是讓改變的configuration更新到當前configuration. (2) 確保所有正在運行的activity都能更新改變后的configuration.(這點是關鍵.) . 我們按照這個思路看看android是如何更新configuration. 查看代碼 , 首先看到 這個函數(shù)首先判斷values是否為空, 這里values肯定不為空的, 然后changes = newConfig.updateFrom(values); 我們看看updateFrom做了什么操作.
  1. /** 
  2.      * Copy the fields from delta into this Configuration object, keeping 
  3.      * track of which ones have changed.  Any undefined fields in 
  4.      * <var>delta</var> are ignored and not copied in to the current 
  5.      * Configuration. 
  6.      * @return Returns a bit mask of the changed fields, as per 
  7.      * {@link #diff}. 
  8.      */  
  9.     public int updateFrom(Configuration delta) {  
  10.         int changed = 0;  
  11.         ...  
  12.         if (delta.locale != null  
  13.                 && (locale == null || !locale.equals(delta.locale))) {  
  14.             changed |= ActivityInfo.CONFIG_LOCALE;  
  15.             locale = delta.locale != null  
  16.                      (Locale) delta.locale.clone() : null;  
  17.             textLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);  
  18.         }  
  19.         if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))  
  20.         {  
  21.             userSetLocale = true;  
  22.             changed |= ActivityInfo.CONFIG_LOCALE;  
  23.         }  
  24.         ...  
  25.         return changed;  
  26.     }  

因為語言改變了, 那么 (!locale.equals(delta.locale)) 是true. changed 大于0, 然后return changed. 回到ActivityManagerService.java的updateConfigurationLocked函數(shù), 因為changed不為0 , 所以走if這個流程.  繼續(xù)看代碼

  1. for (int i=mLruProcesses.size()-1; i>=0; i--) {  
  2.                     ProcessRecord app = mLruProcesses.get(i);  
  3.                     try {  
  4.                         if (app.thread != null) {  
  5.                             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending to proc "  
  6.                                     + app.processName + " new config " + mConfiguration);  
  7.                             app.thread.scheduleConfigurationChanged(configCopy);  
  8.                         }  
  9.                     } catch (Exception e) {  
  10.                     }  
  11.                 }  


首先看到的是mLurProcesses 是ArrayList<ProcessRecord>類型.  LRU : Least Recently Used保存所有運行過的進程.  ProcessRecord進程類, 一個apk文件運行時會對應一個進程. app.thread. 此處的thread代表的是ApplicationThreadNative.java類型.  然后調(diào)用其scheduleConfigurationChanged();  查看該函數(shù)

  1. public final void scheduleConfigurationChanged(Configuration config)  
  2.             throws RemoteException {  
  3.         Parcel data = Parcel.obtain();  
  4.         data.writeInterfaceToken(IApplicationThread.descriptor);  
  5.         config.writeToParcel(data, 0);  
  6.         mRemote.transact(SCHEDULE_CONFIGURATION_CHANGED_TRANSACTION, data, null,  
  7.                 IBinder.FLAG_ONEWAY);  
  8.         data.recycle();  
  9.     }  
 
又是通過binder調(diào)用, 所以 , binder在android中是一個很重要的概念. 此處遠程調(diào)用的是ActivityThread.java中的私有內(nèi)部內(nèi)ApplicationThread

  1.   private class ApplicationThread extends ApplicationThreadNative {  
  2.         private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s";  
  3.         private static final String ONE_COUNT_COLUMN = "%21s %8d";  
  4.         private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";  
  5.         private static final String TWO_COUNT_COLUMNS_DB = "%21s %8d %21s %8d";  
  6.         private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";  
  7.   
  8.   
  9.         ...  
  10.         public void scheduleConfigurationChanged(Configuration config) {  
  11.             updatePendingConfiguration(config);  
  12.             queueOrSendMessage(H.CONFIGURATION_CHANGED, config);  
  13.         }  
  14.         ...  
  15. }  

而ApplicationThread中的handler的CONFIGURATION_CHANGED是調(diào)用handleConfigurationChanged()

  1. final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {  
  2.   
  3.        ArrayList<ComponentCallbacks2> callbacks = null;  
  4.   
  5.     ...         ...  
  6.        applyConfigurationToResourcesLocked(config, compat);  
  7.          
  8.        ...  
  9.          
  10.        callbacks = collectComponentCallbacksLocked(false, config);  
  11.        ...  
  12.          
  13.        if (callbacks != null) {  
  14.            final int N = callbacks.size();  
  15.            for (int i=0; i<N; i++) {  
  16.                performConfigurationChanged(callbacks.get(i), config);  
  17.            }  
  18.        }  

這個函數(shù)首先是調(diào)用applyConfigurationToResourcesLocked(). 看函數(shù)名大概可以推測: 將configuration應用到resources.這里configuration改變的是local 本地語言. 那而resources資源包含不就包含了語言, 圖片這些資源嗎. 

  1. final boolean applyConfigurationToResourcesLocked(Configuration config,  
  2.             CompatibilityInfo compat) {  
  3.           
  4.         int changes = mResConfiguration.updateFrom(config);  
  5.         DisplayMetrics dm = getDisplayMetricsLocked(nulltrue);  
  6.   
  7.   
  8.         if (compat != null && (mResCompatibilityInfo == null ||  
  9.                 !mResCompatibilityInfo.equals(compat))) {  
  10.             mResCompatibilityInfo = compat;  
  11.             changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT  
  12.                     | ActivityInfo.CONFIG_SCREEN_SIZE  
  13.                     | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;  
  14.         }  
  15.   
  16.         ...  
  17.   
  18.         Resources.updateSystemConfiguration(config, dm, compat);  
  19.   
  20.         ...  
  21.           
  22.         Iterator<WeakReference<Resources>> it =  
  23.             mActiveResources.values().iterator();  
  24.         while (it.hasNext()) {  
  25.             WeakReference<Resources> v = it.next();  
  26.             Resources r = v.get();  
  27.             if (r != null) {  
  28.                 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "  
  29.                         + r + " config to: " + config);  
  30.                 r.updateConfiguration(config, dm, compat);  
  31.                 //Slog.i(TAG, "Updated app resources " + v.getKey()  
  32.                 //        + " " + r + ": " + r.getConfiguration());  
  33.             } else {  
  34.                 //Slog.i(TAG, "Removing old resources " + v.getKey());  
  35.                 it.remove();  
  36.             }  
  37.         }  
  38.           
  39.         return changes != 0;  
  40.     }  

Resources.updateSystemConfiguration()清除一部分系統(tǒng)資源, 并且將config更新到Resources, 而Resources包含了一個AssetManager對象, 該對象的核心實現(xiàn)是在AssetManager.cpp中完成的. 然后循環(huán)清空mActivityResources資源. 再回到handleConfigurationChanged()函數(shù), 執(zhí)行完updateSystemConfiguration后, 會循環(huán)該進程的所有activity:

if (callbacks != null) {

            final int N = callbacks.size();
            for (int i=0; i<N; i++) {
                performConfigurationChanged(callbacks.get(i), config);
            }
        }

再來看performConfigurationChanged的實現(xiàn):

  1. private final void performConfigurationChanged(  
  2.             ComponentCallbacks2 cb, Configuration config) {  
  3.         // Only for Activity objects, check that they actually call up to their  
  4.         // superclass implementation.  ComponentCallbacks2 is an interface, so  
  5.         // we check the runtime type and act accordingly.  
  6.         Activity activity = (cb instanceof Activity) ? (Activity) cb : null;  
  7.         if (activity != null) {  
  8.             activity.mCalled = false;  
  9.         }  
  10.   
  11.         boolean shouldChangeConfig = false;  
  12.         if ((activity == null) || (activity.mCurrentConfig == null)) {  
  13.             shouldChangeConfig = true;  
  14.         } else {  
  15.   
  16.             // If the new config is the same as the config this Activity  
  17.             // is already running with then don't bother calling  
  18.             // onConfigurationChanged  
  19.             int diff = activity.mCurrentConfig.diff(config);  
  20.             if (diff != 0) {  
  21.                 // If this activity doesn't handle any of the config changes  
  22.                 // then don't bother calling onConfigurationChanged as we're  
  23.                 // going to destroy it.  
  24.                 if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {  
  25.                     shouldChangeConfig = true;  
  26.                 }  
  27.             }  
  28.         }  
  29.   
  30.         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Config callback " + cb  
  31.                 + ": shouldChangeConfig=" + shouldChangeConfig);  
  32.         if (shouldChangeConfig) {  
  33.             cb.onConfigurationChanged(config);  
  34.   
  35.             if (activity != null) {  
  36.                 if (!activity.mCalled) {  
  37.                     throw new SuperNotCalledException(  
  38.                             "Activity " + activity.getLocalClassName() +  
  39.                         " did not call through to super.onConfigurationChanged()");  
  40.                 }  
  41.                 activity.mConfigChangeFlags = 0;  
  42.                 activity.mCurrentConfig = new Configuration(config);  
  43.             }  
  44.         }  
  45.     }  

該函數(shù)判斷configuration是否改變, 如果改變那么shouldChangeConfig為true. 然后調(diào)用activity的onConfigurationChange(config);

  1. /** 
  2.     * Called by the system when the device configuration changes while your 
  3.     * activity is running.  Note that this will <em>only</em> be called if 
  4.     * you have selected configurations you would like to handle with the 
  5.     * {@link android.R.attr#configChanges} attribute in your manifest.  If 
  6.     * any configuration change occurs that is not selected to be reported 
  7.     * by that attribute, then instead of reporting it the system will stop 
  8.     * and restart the activity (to have it launched with the new 
  9.     * configuration). 
  10.     *  
  11.     * <p>At the time that this function has been called, your Resources 
  12.     * object will have been updated to return resource values matching the 
  13.     * new configuration. 
  14.     *  
  15.     * @param newConfig The new device configuration. 
  16.     */  
  17.    public void onConfigurationChanged(Configuration newConfig) {  
  18.        mCalled = true;  
  19.   
  20.        mFragments.dispatchConfigurationChanged(newConfig);  
  21.   
  22.        if (mWindow != null) {  
  23.            // Pass the configuration changed event to the window  
  24.            mWindow.onConfigurationChanged(newConfig);  
  25.        }  
  26.   
  27.        if (mActionBar != null) {  
  28.            // Do this last; the action bar will need to access  
  29.            // view changes from above.  
  30.            mActionBar.onConfigurationChanged(newConfig);  
  31.        }  
  32.    }  

查看注釋, 大概意思是:  如果你的activity運行 , 設備信息有改變(即configuration改變)時由系統(tǒng)調(diào)用. 如果你在manifest.xml中配置了configChnages屬性則表示有你自己來處理configuration change. 否則就重啟當前這個activity.  而重啟之前, 舊的resources已經(jīng)被清空, 那么就會裝載新的資源, 整個過程就完成了語言切換后 , 能夠讓所有app使用新的語言. 語言切換流程大概分為三步:

第一步:  判斷configuration的local是否已經(jīng)改變, 如果改變則將local更新到當前的configuration

第二步: 清空舊的資源. 

第三步: 重啟所有所有進程并加裝新資源.

由于個人知識水平有限, 有些地方不免有些紕漏, 希望大牛多多指點.  也希望有共同興趣愛好的人進行技術交流.

本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android程序怎樣禁止橫豎屏切換
Android應用程序窗口(Activity)的視圖對象(View)的創(chuàng)建過程分析
Android橫屏豎屏切換總結(jié)
Android程序的真正入口Application
Wifi模塊
Android:實時改變配置
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服