当前位置: 首页 > news >正文

公司建网站空间邵阳网站建设

公司建网站空间,邵阳网站建设,wordpress主机cdn,做直播网站多少钱Android手机语言切换行为#xff0c;是通过设置-语言和输入法-语言来改变手机的语言#xff0c;其实这个功能很少被用户使用。 以Android5.1工程源码为基础,从设置app入手来分析和学习语言切换的过程:一、语言设置界面#xff1a;首先在设置app中找到语言设置这个Preference… Android手机语言切换行为是通过设置-语言和输入法-语言来改变手机的语言其实这个功能很少被用户使用。 以Android5.1工程源码为基础,从设置app入手来分析和学习语言切换的过程: 一、语言设置界面 首先在设置app中找到语言设置这个Preference目前设置中界面大多都是Fragment先找到语言和输入法的PreferenceScreen与其对应的Fragment是InputMethodAndLanguageSettings.java在其onCreate()方法中首先是增加语言设置的preference     [java] view plaincopy addPreferencesFromResource(R.xml.language_settings);   找到language_settings.xml可发现如下代码    [html] view plaincopy PreferenceScreen              android:keyphone_language              android:titlestring/phone_language              android:fragmentcom.android.settings.LocalePicker              /   于是断定LocalePicker就是语言设置的Fragment它是ListFragment的子类继承于framework中LocalePicker,并实现了父类的一个接口其回调方法是onLocaleSelected()Locale中文含义大致是语言环境所以可推测这是设置语言后的一个回调方法不确定的话可打断点测试一下。然而此类中并没有关于语言设置界面数据适配的太多逻辑只是通过父类的方法创建了一个view:    [java] view plaincopy Override     public View onCreateView(             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {         final View view  super.onCreateView(inflater, container, savedInstanceState);         final ListView list  (ListView) view.findViewById(android.R.id.list);         Utils.forcePrepareCustomPreferencesList(container, view, list, false);         return view;     }   所以更多逻辑应该在framework中的LocalePicker.java中。既然是ListFragment那就必须有Adapter,在此类中有构建了一个Adapter [java] view plaincopy /**     * Constructs an Adapter object containing Locale information. Content is sorted by     * {link LocaleInfo#label}.     */     public static ArrayAdapterLocaleInfo constructAdapter(Context context) {         return constructAdapter(context, R.layout.locale_picker_item, R.id.locale);     }     public static ArrayAdapterLocaleInfo constructAdapter(Context context,             final int layoutId, final int fieldId) {         boolean isInDeveloperMode  Settings.Global.getInt(context.getContentResolver(),                 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) ! 0;         //获取系统支持语言的信息         final ListLocaleInfo localeInfos  getAllAssetLocales(context, isInDeveloperMode);         final LayoutInflater inflater                  (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);         return new ArrayAdapterLocaleInfo(context, layoutId, fieldId, localeInfos) {             Override             public View getView(int position, View convertView, ViewGroup parent) {                 View view;                 TextView text;                 if (convertView  null) {                     view  inflater.inflate(layoutId, parent, false);                     text  (TextView) view.findViewById(fieldId);                     view.setTag(text);                 } else {                     view  convertView;                     text  (TextView) view.getTag();                 }                 LocaleInfo item  getItem(position);                 text.setText(item.toString());                 text.setTextLocale(item.getLocale());                 return view;             }         };     }   而此方法通过getAllAssetLocales()方法获取系统支持语言的信息 [java] view plaincopy public static ListLocaleInfo getAllAssetLocales(Context context, boolean isInDeveloperMode) {          final Resources resources  context.getResources();          //获取系统所支持的语言          final String[] locales  Resources.getSystem().getAssets().getLocales();          ListString localeList  new ArrayListString(locales.length);          Collections.addAll(localeList, locales);            // Dont show the pseudolocales unless were in developer mode.           if (!isInDeveloperMode) {              localeList.remove(ar-XB);              localeList.remove(en-XA);          }            Collections.sort(localeList);          final String[] specialLocaleCodes  resources.getStringArray(R.array.special_locale_codes);          final String[] specialLocaleNames  resources.getStringArray(R.array.special_locale_names);            final ArrayListLocaleInfo localeInfos  new ArrayListLocaleInfo(localeList.size());          for (String locale : localeList) {              final Locale l  Locale.forLanguageTag(locale.replace(_, -));              if (l  null || und.equals(l.getLanguage())                      || l.getLanguage().isEmpty() || l.getCountry().isEmpty()) {                  continue;              }                if (localeInfos.isEmpty()) {                  if (DEBUG) {                      Log.v(TAG, adding initial  toTitleCase(l.getDisplayLanguage(l)));                  }                  localeInfos.add(new LocaleInfo(toTitleCase(l.getDisplayLanguage(l)), l));              } else {                  // check previous entry:                  //  same lang and a country - upgrade to full name and                  //    insert ours with full name                  //  diff lang - insert ours with lang-only name                  final LocaleInfo previous  localeInfos.get(localeInfos.size() - 1);                  if (previous.locale.getLanguage().equals(l.getLanguage())                           !previous.locale.getLanguage().equals(zz)) {                      if (DEBUG) {                          Log.v(TAG, backing up and fixing   previous.label   to                                    getDisplayName(previous.locale, specialLocaleCodes, specialLocaleNames));                      }                      previous.label  toTitleCase(getDisplayName(                              previous.locale, specialLocaleCodes, specialLocaleNames));                      if (DEBUG) {                          Log.v(TAG,   and adding  toTitleCase(                                  getDisplayName(l, specialLocaleCodes, specialLocaleNames)));                      }                      localeInfos.add(new LocaleInfo(toTitleCase(                              getDisplayName(l, specialLocaleCodes, specialLocaleNames)), l));                  } else {                      String displayName  toTitleCase(l.getDisplayLanguage(l));                      if (DEBUG) {                          Log.v(TAG, adding displayName);                      }                      localeInfos.add(new LocaleInfo(displayName, l));                  }              }          }            Collections.sort(localeInfos);          return localeInfos;      }   此方法中还会通过Resources.getSystem().getAssets().getLocales()去获得系统支持的语言信息然后添加LocaleInfo里边再通过Adapter适配到ListView中。getLocales()方法属于类AssetManager.java [java] view plaincopy /**      * Get the locales that this asset manager contains data for.      *      * pOn SDK 21 (Android 5.0: Lollipop) and above, Locale strings are valid      * a hrefhttps://tools.ietf.org/html/bcp47BCP-47/a language tags and can be      * parsed using {link java.util.Locale#forLanguageTag(String)}.      *      * pOn SDK 20 (Android 4.4W: Kitkat for watches) and below, locale strings      * are of the form {code ll_CC} where {code ll} is a two letter language code,      * and {code CC} is a two letter country code.      */      public native final String[] getLocales();   乍一看是个native方法那不就是跟JNI有关系了所以只能到相应JNI目录下去找了路径android5.1\frameworks\base\core\jni对应文件android_util_AssetManager.cpp浏览下这个文件发现这个家伙有点不得了啊什么resourcetheme等都跟它有关系,看样子还的加油学学JNI啊!然后找到对应的native方法 [java] view plaincopy static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)  {      VectorString8 locales;        AssetManager* am  assetManagerForJavaObject(env, clazz);      if (am  NULL) {          return NULL;      }        am-getLocales(locales);        const int N  locales.size();        jobjectArray result  env-NewObjectArray(N, g_stringClass, NULL);      if (result  NULL) {          return NULL;      }        for (int i0; iN; i) {          jstring str  env-NewStringUTF(locales[i].string());          if (str  NULL) {              return NULL;          }          env-SetObjectArrayElement(result, i, str);          env-DeleteLocalRef(str);      }        return result;  }   通过上面初步的分析语言的List界面就基本出来了在getAllAssetLocales()方法中打了个断点查看了下locales被赋值以后的值 二、语言设置功能实现过程 上面提到了设置中的LocalePicker类实现了父类接口中的onLocaleSelected()方法    [java] view plaincopy public static interface LocaleSelectionListener {         // You can add any argument if you really need it...         public void onLocaleSelected(Locale locale);     }              Override     public void onLocaleSelected(final Locale locale) {         if (Utils.hasMultipleUsers(getActivity())) {             mTargetLocale  locale;             showDialog(DLG_SHOW_GLOBAL_WARNING);         } else {             getActivity().onBackPressed();             LocalePicker.updateLocale(locale);         }     }   此方法中最终调用了其父类的updateLocale()方法来更新系统的语言环境   [java] view plaincopy /**   * Requests the system to update the system locale. Note that the system looks halted   * for a while during the Locale migration, so the caller need to take care of it.   */   public static void updateLocale(Locale locale) {       try {           IActivityManager am  ActivityManagerNative.getDefault();           Configuration config  am.getConfiguration();           // Will set userSetLocale to indicate this isnt some passing default - the user           // wants this remembered           config.setLocale(locale);           am.updateConfiguration(config);           // Trigger the dirty bit for the Settings Provider.           BackupManager.dataChanged(com.android.providers.settings);       } catch (RemoteException e) {           // Intentionally left blank       }   }   又看到ActivityManagerNative.getDefault()所以可以直接到ActivityManagerService.java中找对应的方法此方法中先是把选择的语言设置到Configuration中记录下来。设置了不代表系统就知道这档子事所以还需要am去更新一下说的俗气一点am老大知道了这档子事然后大吼一声我这里有个东西改变了小伙伴们刷新一下在ActivityManagerService中找到updateConfiguration()方法 [java] view plaincopy public void updateConfiguration(Configuration values) {          enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,                  updateConfiguration());          synchronized(this) {              if (values  null  mWindowManager ! null) {                  // sentinel: fetch the current configuration from the window manager                  values  mWindowManager.computeNewConfiguration();              }              if (mWindowManager ! null) {                  mProcessList.applyDisplaySize(mWindowManager);              }              final long origId  Binder.clearCallingIdentity();              if (values ! null) {                  Settings.System.clearConfiguration(values);              }              updateConfigurationLocked(values, null, false, false);              Binder.restoreCallingIdentity(origId);          }      }   看到Settings.System.clearConfiguration(values)不要以为这里把values清除了额其实这个方法只是把系统字体的特效清除了比如字体的大小    [java] view plaincopy /**          * hide Erase the fields in the Configuration that should be applied          * by the settings.          */          public static void clearConfiguration(Configuration inoutConfig) {              inoutConfig.fontScale  0;          }   然后调用updateConfigurationLocked()方法 [java] view plaincopy /**      * Do either or both things: (1) change the current configuration, and (2)      * make sure the given activity is running with the (now) current      * configuration.  Returns true if the activity has been left running, or      * false if varstarting/var is being destroyed to match the new      * configuration.      * param persistent TODO      */  boolean updateConfigurationLocked(Configuration values,              ActivityRecord starting, boolean persistent, boolean initLocale) {          int changes  0;          if (values ! null) {              Configuration newConfig  new Configuration(mConfiguration);              changes  newConfig.updateFrom(values);              if (changes ! 0) {                  if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {                      Slog.i(TAG, Updating configuration to:   values);                  }                                   EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);                  if (values.locale ! null  !initLocale) {                      saveLocaleLocked(values.locale,                                       !values.locale.equals(mConfiguration.locale),                                       values.userSetLocale);                  }                  mConfigurationSeq;                  if (mConfigurationSeq  0) {                      mConfigurationSeq  1;                  }                  newConfig.seq  mConfigurationSeq;                  mConfiguration  newConfig;                  Slog.i(TAG, Config changes  Integer.toHexString(changes)     newConfig);                  mUsageStatsService.reportConfigurationChange(newConfig, mCurrentUserId);                  //mUsageStatsService.noteStartConfig(newConfig);                  final Configuration configCopy  new Configuration(mConfiguration);                                   // TODO: If our config changes, should we auto dismiss any currently                  // showing dialogs?                  mShowDialogs  shouldShowDialogs(newConfig);                  AttributeCache ac  AttributeCache.instance();                  if (ac ! null) {                      ac.updateConfiguration(configCopy);                  }                  // Make sure all resources in our process are updated                  // right now, so that anyone who is going to retrieve                  // resource values after we return will be sure to get                  // the new ones.  This is especially important during                  // boot, where the first config change needs to guarantee                  // all resources have that config before following boot                  // code is executed.                  mSystemThread.applyConfigurationToResources(configCopy);                  if (persistent  Settings.System.hasInterestingConfigurationChanges(changes)) {                      Message msg  mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);                      msg.obj  new Configuration(configCopy);                      mHandler.sendMessage(msg);                  }                  for (int imLruProcesses.size()-1; i0; i--) {                      ProcessRecord app  mLruProcesses.get(i);                      try {                          if (app.thread ! null) {                              if (DEBUG_CONFIGURATION) Slog.v(TAG, Sending to proc                                        app.processName   new config   mConfiguration);                              app.thread.scheduleConfigurationChanged(configCopy);                          }                      } catch (Exception e) {                      }                  }                  Intent intent  new Intent(Intent.ACTION_CONFIGURATION_CHANGED);                  intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY                          | Intent.FLAG_RECEIVER_REPLACE_PENDING                          | Intent.FLAG_RECEIVER_FOREGROUND);                  broadcastIntentLocked(null, null, intent, null, null, 0, null, null,                          null, AppOpsManager.OP_NONE, false, false, MY_PID,                          Process.SYSTEM_UID, UserHandle.USER_ALL);                  if ((changesActivityInfo.CONFIG_LOCALE) ! 0) {                      intent  new Intent(Intent.ACTION_LOCALE_CHANGED);                      intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);                      broadcastIntentLocked(null, null, intent,                              null, null, 0, null, null, null, AppOpsManager.OP_NONE,                              false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);                  }              }          }          boolean kept  true;          final ActivityStack mainStack  mStackSupervisor.getFocusedStack();          // mainStack is null during startup.          if (mainStack ! null) {              if (changes ! 0  starting  null) {                  // If the configuration changed, and the caller is not already                  // in the process of starting an activity, then find the top                  // activity to check if its configuration needs to change.                  starting  mainStack.topRunningActivityLocked(null);              }              if (starting ! null) {                  kept  mainStack.ensureActivityConfigurationLocked(starting, changes);                  // And we need to make sure at this point that all other activities                  // are made visible with the correct configuration.                  mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);              }          }          if (values ! null  mWindowManager ! null) {              mWindowManager.setNewConfiguration(mConfiguration);          }          return kept;      }   此方法主要做两件事第一改变当前的configuration将新的数据放进去。第二保证正在运行的应用程序界面更新最新的configuration。先调用updateFrom()方法遍历configuration包含的属性是否改变如果有改变就返回一个对应的整数如果没有改变就返回0。就语言改变而言根据上面的分析configuration至少有3个属性发生了改变fontscale之前没有设置字体的效果就不会改变、locale和布局的direction。 有了新的数据就要保存保存在configuration中不是个事。对于Android系统而言改变语言有两个地方的数据需要更新一个是SystemProperties另一个是数据库。前者以键值对的形式存放数据多用于System后者保存于DataBase中多用于应用程序获取算是对外开放的数据。上面方法中对这两个地方都进行了数据保存操作: 1)SystemProperties调用saveLocaleLocked()方法 [java] view plaincopy /**      * Save the locale.  You must be inside a synchronized (this) block.      */      private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {          if(isDiff) {              SystemProperties.set(user.language, l.getLanguage());              SystemProperties.set(user.region, l.getCountry());          }          if(isPersist) {              SystemProperties.set(persist.sys.language, l.getLanguage());              SystemProperties.set(persist.sys.country, l.getCountry());              SystemProperties.set(persist.sys.localevar, l.getVariant());              mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG, l));          }      }   2)database:调用Settings.System.putConfiguration()方法 [java] view plaincopy if (persistent  Settings.System.hasInterestingConfigurationChanges(changes)) {                     Message msg  mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);                     msg.obj  new Configuration(configCopy);                     mHandler.sendMessage(msg);     }     ...     case UPDATE_CONFIGURATION_MSG: {                 final ContentResolver resolver  mContext.getContentResolver();                 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);             } break;   该保存的数据保存了但是Resource还不知道这档子事因为Android代码和资源是分开的Resource不知道Configuration发生了变化Resource就不会去加载正确的资源。所以接下来此方法调用了mSystemThread.applyConfigurationToResources(configCopy)来完成这件事mSystemThread是一个ActivityThread对象其初始化在ActivityManagerService的构造函数中完成    [java] view plaincopy mSystemThread  ActivityThread.currentActivityThread();   [java] view plaincopy //此方法属于ActivityThread      public final void applyConfigurationToResources(Configuration config) {          synchronized (mResourcesManager) {              mResourcesManager.applyConfigurationToResourcesLocked(config, null);          }      }      //此方法属于ResourcesManage      public final boolean applyConfigurationToResourcesLocked(Configuration config,              CompatibilityInfo compat) {          if (mResConfiguration  null) {              mResConfiguration  new Configuration();          }          if (!mResConfiguration.isOtherSeqNewer(config)  compat  null) {              if (DEBUG_CONFIGURATION) Slog.v(TAG, Skipping new config: curSeq                       mResConfiguration.seq  , newSeq  config.seq);              return false;          }          int changes  mResConfiguration.updateFrom(config);          flushDisplayMetricsLocked();          DisplayMetrics defaultDisplayMetrics  getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);          if (compat ! null  (mResCompatibilityInfo  null ||                  !mResCompatibilityInfo.equals(compat))) {              mResCompatibilityInfo  compat;              changes | ActivityInfo.CONFIG_SCREEN_LAYOUT                      | ActivityInfo.CONFIG_SCREEN_SIZE                      | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;          }          // set it for java, this also affects newly created Resources          if (config.locale ! null) {              Locale.setDefault(config.locale);          }          Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);          ApplicationPackageManager.configurationChanged();          //Slog.i(TAG, Configuration changed in   currentPackageName());          Configuration tmpConfig  null;          for (int imActiveResources.size()-1; i0; i--) {              ResourcesKey key  mActiveResources.keyAt(i);              Resources r  mActiveResources.valueAt(i).get();              if (r ! null) {                  if (DEBUG_CONFIGURATION) Slog.v(TAG, Changing resources                            r   config to:   config);                  int displayId  key.mDisplayId;                  boolean isDefaultDisplay  (displayId  Display.DEFAULT_DISPLAY);                  DisplayMetrics dm  defaultDisplayMetrics;                  final boolean hasOverrideConfiguration  key.hasOverrideConfiguration();                  if (!isDefaultDisplay || hasOverrideConfiguration) {                      if (tmpConfig  null) {                          tmpConfig  new Configuration();                      }                      tmpConfig.setTo(config);                      if (!isDefaultDisplay) {                          dm  getDisplayMetricsLocked(displayId);                          applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig);                      }                      if (hasOverrideConfiguration) {                          tmpConfig.updateFrom(key.mOverrideConfiguration);                      }                      r.updateConfiguration(tmpConfig, dm, compat);                  } else {                      r.updateConfiguration(config, dm, compat);                  }                  //Slog.i(TAG, Updated app resources   v.getKey()                  //            r  :   r.getConfiguration());              } else {                  //Slog.i(TAG, Removing old resources   v.getKey());                  mActiveResources.removeAt(i);              }          }          return changes ! 0;      }   此方法中Resource和ApplicationPackageManager都会去更新configurationconfiguration所包含的属性都会遍历到该更新的数据更新该清除的缓存清除。 到这里第一件事算是做完了就要做第二件事让新的configuration更新到所有界面updateConfigurationLocked()方法通过遍历保存在ProcessRecord中的进程然后通过scheduleConfigurationChanged()方法更新它们的configuration [java] view plaincopy for (int imLruProcesses.size()-1; i0; i--) {       ProcessRecord app  mLruProcesses.get(i);       try {            if (app.thread ! null) {            if (DEBUG_CONFIGURATION) Slog.v(TAG, Sending to proc                                        app.processName   new config   mConfiguration);             app.thread.scheduleConfigurationChanged(configCopy);           }       } catch (Exception e) {       }   }   此处通过Binder机制调用ApplicationThreadNative.java中的scheduleConfigurationChanged()方法最后调用到ActivityThread中的内部类ApplicationThread的scheduleConfigurationChanged()方法函数调用堆栈如图 [java] view plaincopy public void scheduleConfigurationChanged(Configuration config) {              updatePendingConfiguration(config);              sendMessage(H.CONFIGURATION_CHANGED, config);      }   [java] view plaincopy case CONFIGURATION_CHANGED:                      Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, configChanged);                      mCurDefaultDisplayDpi  ((Configuration)msg.obj).densityDpi;                      handleConfigurationChanged((Configuration)msg.obj, null);                      Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                      break;   [java] view plaincopy final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {          int configDiff  0;          synchronized (mResourcesManager) {              if (mPendingConfiguration ! null) {                  if (!mPendingConfiguration.isOtherSeqNewer(config)) {                      config  mPendingConfiguration;                      mCurDefaultDisplayDpi  config.densityDpi;                      updateDefaultDensity();                  }                  mPendingConfiguration  null;              }              if (config  null) {                  return;              }                           if (DEBUG_CONFIGURATION) Slog.v(TAG, Handle configuration changed:                        config);              mResourcesManager.applyConfigurationToResourcesLocked(config, compat);              if (mConfiguration  null) {                  mConfiguration  new Configuration();              }              if (!mConfiguration.isOtherSeqNewer(config)  compat  null) {                  return;              }              configDiff  mConfiguration.diff(config);              mConfiguration.updateFrom(config);              config  applyCompatConfiguration(mCurDefaultDisplayDpi);          }          ArrayListComponentCallbacks2 callbacks  collectComponentCallbacks(false, config);          freeTextLayoutCachesIfNeeded(configDiff);          if (callbacks ! null) {              final int N  callbacks.size();              for (int i0; iN; i) {                  performConfigurationChanged(callbacks.get(i), config);              }          }      }   到这里设置语言以后代码跑的流程就基本结束了需要一提的是performConfigurationChanged()方法。为什么要提它呢因为有时候写应用的时候activity需要关注一些configChanged如android:configChangesorientation|keyboardHidden|screenSize然后重写onConfigurationChanged()方法。然而触发这个方法回调的触发点在哪里呢这里就以设置语言为例设置语言触发了configuration的改变。先来看下performConfigurationChanged()方法     [java] view plaincopy private static void performConfigurationChanged(ComponentCallbacks2 cb, Configuration config) {          // Only for Activity objects, check that they actually call up to their          // superclass implementation.  ComponentCallbacks2 is an interface, so          // we check the runtime type and act accordingly.          Activity activity  (cb instanceof Activity) ? (Activity) cb : null;          if (activity ! null) {              activity.mCalled  false;          }          boolean shouldChangeConfig  false;          if ((activity  null) || (activity.mCurrentConfig  null)) {              shouldChangeConfig  true;          } else {              // If the new config is the same as the config this Activity              // is already running with then dont bother calling              // onConfigurationChanged              int diff  activity.mCurrentConfig.diff(config);              if (diff ! 0) {                  // If this activity doesnt handle any of the config changes                  // then dont bother calling onConfigurationChanged as were                  // going to destroy it.                  if ((~activity.mActivityInfo.getRealConfigChanged()  diff)  0) {                      shouldChangeConfig  true;                  }              }          }          if (DEBUG_CONFIGURATION) Slog.v(TAG, Config callback   cb                   : shouldChangeConfig  shouldChangeConfig);          if (shouldChangeConfig) {              cb.onConfigurationChanged(config);              if (activity ! null) {                  if (!activity.mCalled) {                      throw new SuperNotCalledException(                              Activity   activity.getLocalClassName()                            did not call through to super.onConfigurationChanged());                  }                  activity.mConfigChangeFlags  0;                  activity.mCurrentConfig  new Configuration(config);              }          }      }   如果configuration确实改变了那么此方法中就会调用cb.onConfigurationChanged(config)。cb代表ComponentCallbacks2而ComponentCallbacks2 又继承于ComponentCallbacks所以onConfigurationChanged()方法属于ComponentCallbacks同样Activity类也实现了ComponentCallbacks2这个接口如此一来这个回调的过程就连接上了。也充分说明了为什么在configuration改变以后activity关注的config会回调其父类的onConfigurationChanged()方法。 最后就是广播configuration改变了updateConfigurationLocked()广播了ACTION_CONFIGURATION_CHANGED和ACTION_LOCALE_CHANGED使用的方法是broadcastIntentLocked()此方法广播成功返回BROADCAST_SUCCESS。具体就不多说了。 转载于:https://www.cnblogs.com/Free-Thinker/p/5461523.html
http://www.huolong8.cn/news/311304/

相关文章:

  • 网站加速 wordpress苏州百度推广分公司电话
  • 织梦怎么做门户网站在线seo诊断
  • 实验室网站建设的意义做网站能设置关键词在百度中搜索到
  • 网站开发与管理郴州本地网站建设
  • 中明建投建设集团 网站中国建设银行网站进不去
  • 保定的网站建设asp网站文章自动更新
  • WordPress建站 用插件微信公众号制作编辑器
  • 个人网站开发的现状做网站的有什么软件
  • 校园网站建设的缺陷自己电脑做电影网站
  • 网站百科怎么做汕头网站建设制作公司
  • 网站开发流程分为哪几个阶段网站怎么做翻页
  • 教师在哪些网站可以做兼职中文购物网站模板
  • 做网站样式模板网站对联广告
  • react怎么做pc网站网站开发的实训周
  • 游戏网站建设方案南昌seo排名方案
  • 网站软文推广网站阿里巴巴国际站网站建设
  • 做外贸站推广视频网站开发项目
  • 阮一峰的个人网站康展 wordpress
  • 做淘客网站的公司互联网公司设计师都设计什么
  • 新区seo整站优化公司南宁建站模板源码
  • 网站开发者工具下载wordpress安装图片不显示不出来
  • 推荐门户网站建设公司免费名字设计成图案
  • 花钱做网站需要所有权音乐主题资源网站建设
  • 商铺营销推广方案应用商店关键词优化
  • 菲律宾网站网站建设保定网站建
  • 凡诺网站下载免费看黄金的软件
  • 如何帮助网站吸引流量互联网建网站
  • 网站编辑面试问题和答案做网站的困难
  • 优化整站直接用ip做网站
  • 网站建设贰金手指下拉私募网站建设