- 浏览: 677556 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
qinshubao152:
参考:http://www.see-source.com/bl ...
关于android USB Host 串口编程 -
q328965539:
哥们 我做的数据也都是错误的啊····我怎么可以知道自己otg ...
关于android USB Host 串口编程 -
hgkmail:
好文
android中跨进程通讯的4种方式 -
cczscq:
楼主,我这里有个问题!我这里有个自己制作的font.ttf,这 ...
android字体的工作原理 -
blueice1986:
既然springMVC比struts好那么多的话那struts ...
为什么有了Struts 还要Spring MVC
/system/fonts/下:
DroidSans.ttf(英文字体)
DroidSans-Bold.ttf (粗体)
DroidSansFallback.ttf (中文字体)
Roboto-Regular.ttf (系统英文数字文件常规体)
实现思路:
下载好(一般就需要下面两个字体文件,如果不需要切换字母数字,只需要
DroidSansFallback.ttf)
Roboto-Regular.ttf
DroidSansFallback.ttf,覆盖在/system/fonts/下
重启。
问题: 在源码环境,实现不重启和不要root的切换字体。
想要不重启可以切换字体,就要像字体大小和语言切换那样,改动Configration后,
让各个组件刷新从新加载资源。
所以查看源码,
android语言切换是在packages/apps/Settings/com/android/settings/LocalePicker.java的updateLocale()函数中调用.
**
* 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();
config.locale = locale;
// indicate this isn't some passing default - the user wants this remembered
config.userSetLocale = true;
am.updateConfiguration(config);
// Trigger the dirty bit for the Settings Provider.
BackupManager.dataChanged("com.android.providers.settings");
} catch (RemoteException e) {
// Intentionally left blank
}
}
从注释可以看出, 只要本地local改变就会调用该函数. 查看ActivityManagerNative的getDefault()可以看到, 该函数返回的是远程服务对象ActivityManagerServices.java在本地的一个代理. 最终调用的是ActivityManagerService.java中的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);
}
}
该函数, 首先进行的是权限的校验. 然后调用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 <var>starting</var> is being destroyed to match the new
* configuration.
* @param persistent TODO
*/
public boolean updateConfigurationLocked(Configuration values,
ActivityRecord starting, boolean persistent, boolean initLocale) {
int changes = 0;
boolean kept = true;
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, values.simSetLocale);
}
mConfigurationSeq++;
if (mConfigurationSeq <= 0) {
mConfigurationSeq = 1;
}
newConfig.seq = mConfigurationSeq;
mConfiguration = newConfig;
Slog.i(TAG, "Config changed: " + newConfig);
final Configuration configCopy = new Configuration(mConfiguration);
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 i=mLruProcesses.size()-1; i>=0; 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);
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
null, false, false, MY_PID, Process.SYSTEM_UID);
if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
broadcastIntentLocked(null, null,
new Intent(Intent.ACTION_LOCALE_CHANGED),
null, null, 0, null, null,
null, false, false, MY_PID, Process.SYSTEM_UID);
}
}
}
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 = mMainStack.topRunningActivityLocked(null);
}
if (starting != null) {
kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
mMainStack.ensureActivitiesVisibleLocked(starting, changes);
}
if (values != null && mWindowManager != null) {
mWindowManager.setNewConfiguration(mConfiguration);
}
return kept;
}
整个语言切换就在这个函数中完成. 咋一看似乎没感觉到该函数做了哪些事情. 我们首先来看注释: Do either or both things: (1) change the current configuration, and (2)
make sure the given activity is running with the (now) current. configuration大概意思是: 这个函数做了两件事情. (1). 改变当前的configuration. 意思就是让改变的configuration更新到当前configuration. (2) 确保所有正在运行的activity都能更新改变后的configuration.(这点是关键.) . 我们按照这个思路看看android是如何更新configuration. 查看代码 , 首先看到 这个函数首先判断values是否为空, 这里values肯定不为空的, 然后changes = newConfig.updateFrom(values); 我们看看updateFrom做了什么操作.
[java] view plaincopy
/**
* Copy the fields from delta into this Configuration object, keeping
* track of which ones have changed. Any undefined fields in
* <var>delta</var> are ignored and not copied in to the current
* Configuration.
* @return Returns a bit mask of the changed fields, as per
* {@link #diff}.
*/
public int updateFrom(Configuration delta) {
int changed = 0;
...
if (delta.locale != null
&& (locale == null || !locale.equals(delta.locale))) {
changed |= ActivityInfo.CONFIG_LOCALE;
locale = delta.locale != null
? (Locale) delta.locale.clone() : null;
textLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);
}
if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
{
userSetLocale = true;
changed |= ActivityInfo.CONFIG_LOCALE;
}
...
return changed;
}
因为语言改变了, 那么 (!locale.equals(delta.locale)) 是true. changed 大于0, 然后return changed. 回到ActivityManagerService.java的updateConfigurationLocked函数, 因为changed不为0 , 所以走if这个流程. 继续看代码
[java] view plaincopy
for (int i=mLruProcesses.size()-1; i>=0; 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) {
}
}
首先看到的是mLurProcesses 是ArrayList<ProcessRecord>类型. LRU : Least Recently Used保存所有运行过的进程. ProcessRecord进程类, 一个apk文件运行时会对应一个进程. app.thread. 此处的thread代表的是ApplicationThreadNative.java类型. 然后调用其scheduleConfigurationChanged(); 查看该函数
[java] view plaincopy
public final void scheduleConfigurationChanged(Configuration config)
throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
config.writeToParcel(data, 0);
mRemote.transact(SCHEDULE_CONFIGURATION_CHANGED_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
又是通过binder调用, 所以 , binder在android中是一个很重要的概念. 此处远程调用的是ActivityThread.java中的私有内部内ApplicationThread
[java] view plaincopy
private class ApplicationThread extends ApplicationThreadNative {
private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%21s %8d";
private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
private static final String TWO_COUNT_COLUMNS_DB = "%21s %8d %21s %8d";
private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";
...
public void scheduleConfigurationChanged(Configuration config) {
updatePendingConfiguration(config);
queueOrSendMessage(H.CONFIGURATION_CHANGED, config);
}
...
}
而ApplicationThread中的handler的CONFIGURATION_CHANGED是调用handleConfigurationChanged()
[java] view plaincopy
final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
ArrayList<ComponentCallbacks2> callbacks = null;
... ...
applyConfigurationToResourcesLocked(config, compat);
...
callbacks = collectComponentCallbacksLocked(false, config);
...
if (callbacks != null) {
final int N = callbacks.size();
for (int i=0; i<N; i++) {
performConfigurationChanged(callbacks.get(i), config);
}
}
这个函数首先是调用applyConfigurationToResourcesLocked(). 看函数名大概可以推测: 将configuration应用到resources.这里configuration改变的是local 本地语言. 那而resources资源包含不就包含了语言, 图片这些资源吗.
[java] view plaincopy
final boolean applyConfigurationToResourcesLocked(Configuration config,
CompatibilityInfo compat) {
int changes = mResConfiguration.updateFrom(config);
DisplayMetrics dm = getDisplayMetricsLocked(null, true);
if (compat != null && (mResCompatibilityInfo == null ||
!mResCompatibilityInfo.equals(compat))) {
mResCompatibilityInfo = compat;
changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
| ActivityInfo.CONFIG_SCREEN_SIZE
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
}
...
Resources.updateSystemConfiguration(config, dm, compat);
...
Iterator<WeakReference<Resources>> it =
mActiveResources.values().iterator();
while (it.hasNext()) {
WeakReference<Resources> v = it.next();
Resources r = v.get();
if (r != null) {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+ r + " config to: " + config);
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());
it.remove();
}
}
return changes != 0;
}
Resources.updateSystemConfiguration()清除一部分系统资源, 并且将config更新到Resources, 而Resources包含了一个AssetManager对象, 该对象的核心实现是在AssetManager.cpp中完成的. 然后循环清空mActivityResources资源. 再回到handleConfigurationChanged()函数, 执行完updateSystemConfiguration后, 会循环该进程的所有activity:
if (callbacks != null) {
final int N = callbacks.size();
for (int i=0; i<N; i++) {
performConfigurationChanged(callbacks.get(i), config);
}
}
再来看performConfigurationChanged的实现:
[java] view plaincopy
private final 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 don't bother calling
// onConfigurationChanged
int diff = activity.mCurrentConfig.diff(config);
if (diff != 0) {
// If this activity doesn't handle any of the config changes
// then don't bother calling onConfigurationChanged as we're
// 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是否改变, 如果改变那么shouldChangeConfig为true. 然后调用activity的onConfigurationChange(config);
[java] view plaincopy
/**
* Called by the system when the device configuration changes while your
* activity is running. Note that this will <em>only</em> be called if
* you have selected configurations you would like to handle with the
* {@link android.R.attr#configChanges} attribute in your manifest. If
* any configuration change occurs that is not selected to be reported
* by that attribute, then instead of reporting it the system will stop
* and restart the activity (to have it launched with the new
* configuration).
*
* <p>At the time that this function has been called, your Resources
* object will have been updated to return resource values matching the
* new configuration.
*
* @param newConfig The new device configuration.
*/
public void onConfigurationChanged(Configuration newConfig) {
mCalled = true;
mFragments.dispatchConfigurationChanged(newConfig);
if (mWindow != null) {
// Pass the configuration changed event to the window
mWindow.onConfigurationChanged(newConfig);
}
if (mActionBar != null) {
// Do this last; the action bar will need to access
// view changes from above.
mActionBar.onConfigurationChanged(newConfig);
}
}
查看注释, 大概意思是: 如果你的activity运行 , 设备信息有改变(即configuration改变)时由系统调用. 如果你在manifest.xml中配置了configChnages属性则表示有你自己来处理configuration change. 否则就重启当前这个activity. 而重启之前, 旧的resources已经被清空, 那么就会装载新的资源, 整个过程就完成了语言切换后 , 能够让所有app使用新的语言. 语言切换流程大概分为三步:
第一步: 判断configuration的local是否已经改变, 如果改变则将local更新到当前的configuration
第二步: 清空旧的资源.
第三步: 重启所有所有进程并加装新资源.
能让activity响应的关键是接口ComponentCallbacks
DroidSans.ttf(英文字体)
DroidSans-Bold.ttf (粗体)
DroidSansFallback.ttf (中文字体)
Roboto-Regular.ttf (系统英文数字文件常规体)
实现思路:
下载好(一般就需要下面两个字体文件,如果不需要切换字母数字,只需要
DroidSansFallback.ttf)
Roboto-Regular.ttf
DroidSansFallback.ttf,覆盖在/system/fonts/下
重启。
问题: 在源码环境,实现不重启和不要root的切换字体。
想要不重启可以切换字体,就要像字体大小和语言切换那样,改动Configration后,
让各个组件刷新从新加载资源。
所以查看源码,
android语言切换是在packages/apps/Settings/com/android/settings/LocalePicker.java的updateLocale()函数中调用.
**
* 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();
config.locale = locale;
// indicate this isn't some passing default - the user wants this remembered
config.userSetLocale = true;
am.updateConfiguration(config);
// Trigger the dirty bit for the Settings Provider.
BackupManager.dataChanged("com.android.providers.settings");
} catch (RemoteException e) {
// Intentionally left blank
}
}
从注释可以看出, 只要本地local改变就会调用该函数. 查看ActivityManagerNative的getDefault()可以看到, 该函数返回的是远程服务对象ActivityManagerServices.java在本地的一个代理. 最终调用的是ActivityManagerService.java中的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);
}
}
该函数, 首先进行的是权限的校验. 然后调用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 <var>starting</var> is being destroyed to match the new
* configuration.
* @param persistent TODO
*/
public boolean updateConfigurationLocked(Configuration values,
ActivityRecord starting, boolean persistent, boolean initLocale) {
int changes = 0;
boolean kept = true;
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, values.simSetLocale);
}
mConfigurationSeq++;
if (mConfigurationSeq <= 0) {
mConfigurationSeq = 1;
}
newConfig.seq = mConfigurationSeq;
mConfiguration = newConfig;
Slog.i(TAG, "Config changed: " + newConfig);
final Configuration configCopy = new Configuration(mConfiguration);
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 i=mLruProcesses.size()-1; i>=0; 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);
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
null, false, false, MY_PID, Process.SYSTEM_UID);
if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
broadcastIntentLocked(null, null,
new Intent(Intent.ACTION_LOCALE_CHANGED),
null, null, 0, null, null,
null, false, false, MY_PID, Process.SYSTEM_UID);
}
}
}
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 = mMainStack.topRunningActivityLocked(null);
}
if (starting != null) {
kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
mMainStack.ensureActivitiesVisibleLocked(starting, changes);
}
if (values != null && mWindowManager != null) {
mWindowManager.setNewConfiguration(mConfiguration);
}
return kept;
}
整个语言切换就在这个函数中完成. 咋一看似乎没感觉到该函数做了哪些事情. 我们首先来看注释: Do either or both things: (1) change the current configuration, and (2)
make sure the given activity is running with the (now) current. configuration大概意思是: 这个函数做了两件事情. (1). 改变当前的configuration. 意思就是让改变的configuration更新到当前configuration. (2) 确保所有正在运行的activity都能更新改变后的configuration.(这点是关键.) . 我们按照这个思路看看android是如何更新configuration. 查看代码 , 首先看到 这个函数首先判断values是否为空, 这里values肯定不为空的, 然后changes = newConfig.updateFrom(values); 我们看看updateFrom做了什么操作.
[java] view plaincopy
/**
* Copy the fields from delta into this Configuration object, keeping
* track of which ones have changed. Any undefined fields in
* <var>delta</var> are ignored and not copied in to the current
* Configuration.
* @return Returns a bit mask of the changed fields, as per
* {@link #diff}.
*/
public int updateFrom(Configuration delta) {
int changed = 0;
...
if (delta.locale != null
&& (locale == null || !locale.equals(delta.locale))) {
changed |= ActivityInfo.CONFIG_LOCALE;
locale = delta.locale != null
? (Locale) delta.locale.clone() : null;
textLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);
}
if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
{
userSetLocale = true;
changed |= ActivityInfo.CONFIG_LOCALE;
}
...
return changed;
}
因为语言改变了, 那么 (!locale.equals(delta.locale)) 是true. changed 大于0, 然后return changed. 回到ActivityManagerService.java的updateConfigurationLocked函数, 因为changed不为0 , 所以走if这个流程. 继续看代码
[java] view plaincopy
for (int i=mLruProcesses.size()-1; i>=0; 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) {
}
}
首先看到的是mLurProcesses 是ArrayList<ProcessRecord>类型. LRU : Least Recently Used保存所有运行过的进程. ProcessRecord进程类, 一个apk文件运行时会对应一个进程. app.thread. 此处的thread代表的是ApplicationThreadNative.java类型. 然后调用其scheduleConfigurationChanged(); 查看该函数
[java] view plaincopy
public final void scheduleConfigurationChanged(Configuration config)
throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
config.writeToParcel(data, 0);
mRemote.transact(SCHEDULE_CONFIGURATION_CHANGED_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
又是通过binder调用, 所以 , binder在android中是一个很重要的概念. 此处远程调用的是ActivityThread.java中的私有内部内ApplicationThread
[java] view plaincopy
private class ApplicationThread extends ApplicationThreadNative {
private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%21s %8d";
private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
private static final String TWO_COUNT_COLUMNS_DB = "%21s %8d %21s %8d";
private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";
...
public void scheduleConfigurationChanged(Configuration config) {
updatePendingConfiguration(config);
queueOrSendMessage(H.CONFIGURATION_CHANGED, config);
}
...
}
而ApplicationThread中的handler的CONFIGURATION_CHANGED是调用handleConfigurationChanged()
[java] view plaincopy
final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
ArrayList<ComponentCallbacks2> callbacks = null;
... ...
applyConfigurationToResourcesLocked(config, compat);
...
callbacks = collectComponentCallbacksLocked(false, config);
...
if (callbacks != null) {
final int N = callbacks.size();
for (int i=0; i<N; i++) {
performConfigurationChanged(callbacks.get(i), config);
}
}
这个函数首先是调用applyConfigurationToResourcesLocked(). 看函数名大概可以推测: 将configuration应用到resources.这里configuration改变的是local 本地语言. 那而resources资源包含不就包含了语言, 图片这些资源吗.
[java] view plaincopy
final boolean applyConfigurationToResourcesLocked(Configuration config,
CompatibilityInfo compat) {
int changes = mResConfiguration.updateFrom(config);
DisplayMetrics dm = getDisplayMetricsLocked(null, true);
if (compat != null && (mResCompatibilityInfo == null ||
!mResCompatibilityInfo.equals(compat))) {
mResCompatibilityInfo = compat;
changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
| ActivityInfo.CONFIG_SCREEN_SIZE
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
}
...
Resources.updateSystemConfiguration(config, dm, compat);
...
Iterator<WeakReference<Resources>> it =
mActiveResources.values().iterator();
while (it.hasNext()) {
WeakReference<Resources> v = it.next();
Resources r = v.get();
if (r != null) {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+ r + " config to: " + config);
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());
it.remove();
}
}
return changes != 0;
}
Resources.updateSystemConfiguration()清除一部分系统资源, 并且将config更新到Resources, 而Resources包含了一个AssetManager对象, 该对象的核心实现是在AssetManager.cpp中完成的. 然后循环清空mActivityResources资源. 再回到handleConfigurationChanged()函数, 执行完updateSystemConfiguration后, 会循环该进程的所有activity:
if (callbacks != null) {
final int N = callbacks.size();
for (int i=0; i<N; i++) {
performConfigurationChanged(callbacks.get(i), config);
}
}
再来看performConfigurationChanged的实现:
[java] view plaincopy
private final 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 don't bother calling
// onConfigurationChanged
int diff = activity.mCurrentConfig.diff(config);
if (diff != 0) {
// If this activity doesn't handle any of the config changes
// then don't bother calling onConfigurationChanged as we're
// 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是否改变, 如果改变那么shouldChangeConfig为true. 然后调用activity的onConfigurationChange(config);
[java] view plaincopy
/**
* Called by the system when the device configuration changes while your
* activity is running. Note that this will <em>only</em> be called if
* you have selected configurations you would like to handle with the
* {@link android.R.attr#configChanges} attribute in your manifest. If
* any configuration change occurs that is not selected to be reported
* by that attribute, then instead of reporting it the system will stop
* and restart the activity (to have it launched with the new
* configuration).
*
* <p>At the time that this function has been called, your Resources
* object will have been updated to return resource values matching the
* new configuration.
*
* @param newConfig The new device configuration.
*/
public void onConfigurationChanged(Configuration newConfig) {
mCalled = true;
mFragments.dispatchConfigurationChanged(newConfig);
if (mWindow != null) {
// Pass the configuration changed event to the window
mWindow.onConfigurationChanged(newConfig);
}
if (mActionBar != null) {
// Do this last; the action bar will need to access
// view changes from above.
mActionBar.onConfigurationChanged(newConfig);
}
}
查看注释, 大概意思是: 如果你的activity运行 , 设备信息有改变(即configuration改变)时由系统调用. 如果你在manifest.xml中配置了configChnages属性则表示有你自己来处理configuration change. 否则就重启当前这个activity. 而重启之前, 旧的resources已经被清空, 那么就会装载新的资源, 整个过程就完成了语言切换后 , 能够让所有app使用新的语言. 语言切换流程大概分为三步:
第一步: 判断configuration的local是否已经改变, 如果改变则将local更新到当前的configuration
第二步: 清空旧的资源.
第三步: 重启所有所有进程并加装新资源.
能让activity响应的关键是接口ComponentCallbacks
发表评论
-
Android的权限机制总结
2013-12-16 11:07 23017Android 安全机制概述 ... -
Android的权限机制之—— “沙箱”机制sharedUserId和签名
2013-12-13 11:29 14701Android“沙箱”的本质是为了实现不同应用程序和进程之 ... -
AIL(Android init Language)
2013-12-03 14:16 1914AIL(init.rc) Init.rc是i ... -
Android源码下编译自己的so库
2013-11-07 17:33 2933环境:win7 64位,虚拟机ubuntu10.04,TI ... -
修改framework代码使锁屏完全透明
2013-11-04 14:30 13901,修改KeyguardViewManager.java的ma ... -
开机动画流程
2013-11-01 10:30 14171、开机动画程序bootanimation程序目录:fram ... -
Android 软件测试日志文件抓取
2013-10-17 10:43 37981 log文件分类简介 实时打印的主要有: ... -
android 驱动开发介绍
2013-10-10 11:12 7779前言 意外在网上发现了这扁文章,看后感觉很有必要分享,所 ... -
Android系统Recovery工作原理之使用update.zip
2013-09-13 11:06 97921 总述 为了方便客户日后的固件升级,本周研究 ... -
android 升级策略
2013-09-12 09:50 1170Android系统而言升级意味着二个方面的升级 一个是系 ... -
Android FactoryTest 流程
2013-09-10 17:52 2727Android内置的Factory Test(有测试模式/工 ... -
Ubuntu下ADB调试Android找不到设备的解决方法
2013-09-10 10:13 2004首先确认,我已经在的settings-application ... -
系统移植之为Android启动加速
2013-05-15 13:50 3135Android的启动速度一直以来是他的诟病,虽然现在And ... -
Android系统做了哪些优化?
2013-04-23 10:11 1460Android系统框架和上层应用是类java( ... -
CM10之Setting的快速设置面板按钮布局
2013-04-19 16:03 1842开发环境 ubuntu12.04-desktop-amd6 ... -
Android编译CPU架构体系不同引起的错误解决方法
2013-04-19 10:53 5346转至http://blog.csdn.net/canjian ... -
android系统硬件抽象层(HAL)原理及实现之原理
2013-04-17 15:48 4173Android系统硬件抽象层(HAL)原理 在androi ... -
正确了解ROM,基带,以及RIL
2013-04-17 15:45 5867一、正确了解ROM,基带,以及RIL。 1)、R ... -
Android系统开发之修改调试SystemUI
2013-04-11 10:44 3979开发环境 ubuntu12.04-desktop-amd6 ... -
下载cm10.1源码编译
2013-03-21 10:43 2830开发环境 http://dengzhangta ...
相关推荐
总结来说,搭建Android 4.0与MyEclipse 9的整合开发环境需要安装JDK、MyEclipse、Android SDK和ADT插件,并配置相应的环境变量。通过以上步骤,开发者可以拥有一个完整的环境,用于开发和测试Android 4.0应用程序。
### Android 4.0 Compatibility Definition #### 1. Introduction Android 4.0, also known as Ice Cream Sandwich, was a significant update that brought a range of improvements and new features to the ...
在 Android 系统中,字体大小的变化是由 `android.content.res.Configuration` 类中的 `fontScale` 控制的。因此,要实现应用字体大小的动态调整,我们需要修改 `fontScale` 为我们自己设置的数值。 为了实现应用...
本文将深入探讨如何实现这一功能,主要基于提供的标题"Android 设置全局字体大小"和描述"通过自定义style,从主题中动态设置app全局字体的Demo"。 首先,我们要理解Android中的文本大小单位。在Android中,我们通常...
通过深入研究Configuration类的源码,开发者可以更好地理解和控制应用程序在设备配置变化时的行为,从而提供更优秀的用户体验。对于进行性能优化和适配不同设备的开发者来说,这一知识尤为关键。
### Android CTS 4.0 测试完全教程 #### 一、测试环境搭建 为了进行Android 4.0的CTS(Compatibility Test Suite)测试,首先需要确保搭建好正确的测试环境。以下步骤详细介绍了如何在Linux系统上搭建测试所需的...
首先,我们要明白Android中的字体大小可以通过样式(Style)和主题(Theme)进行全局设置。在AndroidManifest.xml中,我们可以定义一个自定义的主题,并在应用级别或者活动级别应用它。例如: ```xml android:...
Android 4.0 (Ice Cream Sandwich) 和 Android 2.3 (Gingerbread) 在触摸屏(TP)代码方面存在一些显著的区别,这些差异主要涉及驱动程序和输入设备配置文件的处理。在 Android 2.3 上,调试 TP 通常相对简单,只需...
Source Insight是一款深受程序员喜爱的源代码阅读和编辑工具,其4.0版本在功能和用户体验上更上一层楼。本文将详细介绍如何利用提供的“si4 2018-2-6.xml”配置文件,实现Source Insight 4.0的经典绿色护眼配置,让...
开发者需要在AppWidgetProvider的各个回调方法中处理相应的逻辑,确保Widget的正确显示和功能。 除此之外,Android还提供了AppWidgetOptions,这是一个可以存储额外信息的类,允许开发者为每个实例化的Widget提供...
### Spring 4.0 中 @Configuration 的使用详解 #### 一、@Configuration 基础概念及使用场景 - **@Configuration** 注解自 Spring 3.0 引入,旨在提供一种基于 Java 的配置方式来替代传统的 XML 配置文件。通过...
将IBatis.NET 1.92 1.6.2版本的库在.NET 4.0下应用。结果发现总是报错Ambiguous match found 经过参考资料,重新整理了ibatis的资料,原因如下: iBatis中使用了Castle.DynamicProxy 1.5 而Castle.DynamicProxy ...
在Android应用开发中,组件化是一种先进的架构设计思想,它将复杂的系统拆分成可独立开发、测试和维护的模块,从而提高代码的可复用性和可维护性。本"Android组件化demo"提供了实践组件化的实例,通过在`gradle....
`Configuration`是Android系统用来存储和传递设备配置信息的类,它包含了屏幕方向、字体大小、语言、地区、屏幕密度等信息。当这些配置发生改变时,例如设备旋转或用户切换语言,Android会创建一个新的`...
在Android开发中,用户可以根据自己的视觉需求在系统设置中调整全局字体大小,但这通常会影响到所有安装的应用程序。然而,有时开发者可能希望应用内的字体大小保持固定,不随系统的字体大小设置变化。这篇教程将...
11. **MVC配置优化**:在SpringMVC 4.0中,可以使用Java配置替代XML配置,通过@Configuration和@Bean注解来定义bean和它们之间的关系,使得配置更清晰、更易于维护。 12. **Servlet 3.0支持**:SpringMVC 4.0充分...
Spring 4.0.x 更加注重Java配置,`@Configuration` 类可以替代传统的XML配置,使得配置更加简洁和直观。同时,`@EnableXXX` 注解用于启用特定的 Spring 功能,如 `@EnableWebMvc` 启用 MVC 功能。 九、Spring Boot ...
汽车电子领域,由于车载系统对数据处理速度和稳定性要求较高,SD 4.0 提供的高速接口和优化的功耗管理成为理想的存储解决方案。此外,对于摄影设备、视频编辑工作站、无人机等需要快速读写大量数据的设备,UHS-II...
EnterpriseLibrary4.0是微软发布的一个企业级开发框架,它主要为.NET开发者提供了一系列可重用的、设计良好的软件组件,以帮助简化常见的应用程序开发任务。这个框架是Microsoft Patterns & Practices团队的产品,它...