Andorid 系统中configuration是一个很重要的模块,我们旋转屏幕,低电量等系统配置变化时就会激发configuration改变的事件,configurationChanged事件会导致两种效果,对于不支持onConfigurationChanged事件的Activity,则relauncher它,否则直接调用它的onConfigurationChanged
Configuration更新主要有两个源,一个是当我们旋转屏幕时,还有一个是每当有新的Activityresumed时会更新Configuration,如果Configuration有改变就会通知系统各个单元Configuration改变了,目标主要是Activity和Service.
激发点一:rotation
当系统屏幕旋转时,最后会调用到setRoataion
4550 public void setRotation(int rotation,
4551 boolean alwaysSendConfiguration, int animFlags) {
4557
setRotationUnchecked(rotation,alwaysSendConfiguration, animFlags);
4558 }
5274 public void setRotationUnchecked(int rotation,
5275 boolean alwaysSendConfiguration, int animFlags) {
5276 if(DEBUG_ORIENTATION) Slog.v(TAG,
5277 "setRotationUnchecked(rotation=" +rotation +
5278 " alwaysSendConfiguration=" +alwaysSendConfiguration +
5279 " animFlags=" + animFlags);
5280
5281 long origId = Binder.clearCallingIdentity();
5282 boolean changed;
5283 synchronized(mWindowMap) {
5284
changed =setRotationUncheckedLocked(rotation, animFlags, false);
5285 }
5286
5287 if (changed || alwaysSendConfiguration) {
//这个是真正激发Configuration更新事件的函数
5288
sendNewConfiguration();
5289 }
5290
5291 Binder.restoreCallingIdentity(origId);
5292 }
5834 void sendNewConfiguration() {
5835 try {
5836 mActivityManager.updateConfiguration(null);
5837 } catch (RemoteException e) {
5838 }
5839 }
AMS:
11423 public void updateConfiguration(Configuration values) {
11424 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11425 "updateConfiguration()");
11426
11427 synchronized(this) {
11428 if (values == null && mWindowManager != null) {
11429 // sentinel: fetch the current configuration from thewindow manager
11430
values =mWindowManager.computeNewConfiguration();
11431 }
11432
11433 final long origId = Binder.clearCallingIdentity();
11434 updateConfigurationLocked(values, null);
11435 Binder.restoreCallingIdentity(origId);
11436 }
11437 }
激发点二:resumeTopActivity
1540 boolean updated = false;
1542 synchronized (mService) {
1543 Configuration config =mService.mWindowManager.updateOrientationFromAppTokens(
1544 mService.mConfiguration,
1545 next.mayFreezeScreenLocked(next.app) ?next : null);
1546 if (config != null) {
1547 next.frozenBeforeDestroy = true;
1548 }
1549
updated =mService.updateConfigurationLocked(config, next);
1550 }
每次有一个Activity重新Resume时都会执行configuration的更新
这里是Configuration更新的开始:
1446 public boolean updateConfigurationLocked(Configuration values,
11447 ActivityRecord starting) {
11448 int changes = 0;
11449
11450 boolean kept = true;
11451
11452 if (values != null) {
11453 Configuration newConfig = newConfiguration(mConfiguration);
11454 changes = newConfig.updateFrom(values);
11455 if (changes != 0) {
11456 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
11457 Slog.i(TAG, "Updating configuration to: "+ values);
11458 }
11459
11472 newConfig.seq = mConfigurationSeq;
11473 mConfiguration = newConfig;
11512 if (changes != 0 && starting == null) {
11513 // If the configuration changed, and the caller is notalready
11514 // in the process of starting an activity, then find thetop
11515 // activity to check if its configuration needs tochange.
11516starting =mMainStack.topRunningActivityLocked(null);
11517 }
11518
11519 if (starting != null) {
//所有的activity都要执行configuration检测,如果starting被detroy,则其他activity在这个ActivityresumeTopActivity时会重新执行,所以这个判断条件只是为了减少一次操作。
11520 kept =mMainStack.ensureActivityConfigurationLocked(starting, changes);
11521 if (kept) {
//现在这个判断条件已经去掉了,在honeyComb
11522 // If this didn't result in the starting activitybeing
11523 // destroyed, then we need to make sure at this pointthat all
11524 // other activities are made visible.
11527mMainStack.ensureActivitiesVisibleLocked(starting, changes);
11528 }
11529 }
11530
11531 if (values != null && mWindowManager != null) {
11532 mWindowManager.setNewConfiguration(mConfiguration);
11533 }
11534 return kept;
}
3417 final boolean ensureActivityConfigurationLocked(ActivityRecord r,
3418 int globalChanges) {
3428 // Short circuit: if the two configurations are the exact same
3429 // object (the common case), then there is nothing to do.
3430 Configuration newConfig = mService.mConfiguration;
3431 if (r.configuration == newConfig) {
3434
return true;
3435 }
3445 // Okay we now are going to make this activity have the newconfig.
3446 // But then we need to figure out how it needs to deal withthat.
3447 Configuration oldConfig = r.configuration;
3448 r.configuration = newConfig;
3459 // Figure out what has changed between the two configurations.
3460 int changes = oldConfig.diff(newConfig);
3467 if ((changes&(~r.info.configChanges))!= 0) {
//上面的红色部分是比较重要的,如果Activity配置了自己处理的Config则只会调用下面的scheduleActivityConfigurationChanged,而不是relaunchActivityLocked
3468 // Aha, the activity isn't handling the change, so DIE DIEDIE.
3469 r.configChangeFlags |= changes;
3470 r.startFreezingScreenLocked(r.app, globalChanges);
3471 if (r.app == null || r.app.thread == null) {
3474
destroyActivityLocked(r, true);
3475 } else if (r.state == ActivityState.PAUSING) {
3476 // A little annoying: we are waiting for this activityto
3477 // finish pausing. Let's not do anything now, but just
3478 // flag that it needs to be restarted when donepausing.
3481 r.configDestroy = true;
3482 return true;
3483 } else if (r.state == ActivityState.RESUMED) {
3484 // Try to optimize this case: the configuration ischanging
3485 // and we need to restart the top, resumed activity.
3486 // Instead of doing the normal handshaking, just say
3487 // "restart!".
3490 relaunchActivityLocked(r, r.configChangeFlags, true);
//运行中则重新启动activity
3491 r.configChangeFlags = 0;
3492 } else {
3495 relaunchActivityLocked(r, r.configChangeFlags,false);
3496 r.configChangeFlags = 0;
3497 }
3498
3499 // All done... tell the caller we weren't able to keepthis
3500 // activity around.
3501 return false;
3502 }
3503
3504 // Default case: the activity can handle this newconfiguration, so
3505 // hand it over. Note that we don't need to give it the new
3506 // configuration, since we always send configuration changes toall
3507 // process when they happen so it can just use whateverconfiguration
3508 // it last got.
3509 if (r.app != null && r.app.thread != null) {
3510 try {
3512 r.app.thread.scheduleActivityConfigurationChanged(r);
//用户配置了可以处理的configurationChange事件
3513 } catch (RemoteException e) {
3514 // If process died, whatever.
3515 }
3516 }
}
895 final void ensureActivitiesVisibleLocked(ActivityRecord top,
896 ActivityRecord starting, String onlyThisProcess, intconfigChanges) {
901 // If the top activity is not fullscreen, then we need to
902 // make sure any activities under it are now visible.
903 final int count = mHistory.size();
904 int i = count-1;
905 while (mHistory.get(i) != top) {
906 i--;
907 }
908 ActivityRecord r;
909 boolean behindFullscreen = false;
910 for (; i>=0; i--) {
911 r = (ActivityRecord)mHistory.get(i);
915 if (r.finishing) {
916 continue;
917 }
918
919 final boolean doThisProcess = onlyThisProcess == null
920 || onlyThisProcess.equals(r.processName);
921
922 // First: if this is not the current activity beingstarted, make
923 // sure it matches the current configuration.
924 if (r != starting && doThisProcess) {
925 ensureActivityConfigurationLocked(r, 0);
926 }
}
前面都是检测Config是否变化,以及辅助操作,下面的updateConfigurationLocked才是真正通知Activity,Service的地方
12535 public boolean updateConfigurationLocked(Configuration values,
12536 ActivityRecord starting) {
12585 for (int i=mLruProcesses.size()-1; i>=0; i--) {
12586 ProcessRecord app = mLruProcesses.get(i);
12587 try {
12588 if (app.thread != null ) {
12589app.thread.scheduleConfigurationChanged(mConfiguration);
12592 }
12593 } catch (Exception e) {
12594 }
12595 }
}
无论是service,还是activity都在ActivityManagerService里有一个ProcessRecord.
Activity一侧:
618 public void scheduleConfigurationChanged(Configurationconfig) {
619 synchronized (mPackages) {
620 if (mPendingConfiguration == null ||
621 mPendingConfiguration.isOtherSeqNewer(config)) {
622 mPendingConfiguration = config;
623 }
624 }
625queueOrSendMessage(H.CONFIGURATION_CHANGED, config);
626 }
caseCONFIGURATION_CHANGED:
1097handleConfigurationChanged((Configuration)msg.obj, null);
1098 break;
3371 final void handleConfigurationChanged(Configuration config,CompatibilityInfo compat) {
3372
3373 ArrayList<ComponentCallbacks> callbacks = null;
3374
3375 synchronized (mPackages) {
3376 if (mPendingConfiguration != null) {
3377 if (!mPendingConfiguration.isOtherSeqNewer(config)) {
3378 config = mPendingConfiguration;
3379 }
3380 mPendingConfiguration = null;
3381 }
3382
3383 if (config == null) {
3384 return;
3385 }
3390 applyConfigurationToResourcesLocked(config, compat);
3391
3392 if (mConfiguration == null) {
3393 mConfiguration = new Configuration();
3394 }
3395 if (!mConfiguration.isOtherSeqNewer(config) &&compat == null) {
3396 return;
3397 }
3398 mConfiguration.updateFrom(config);
3399 if (mCompatConfiguration == null) {
3400 mCompatConfiguration = new Configuration();
3401 }
3402 mCompatConfiguration.setTo(mConfiguration);
3403 if (mResCompatibilityInfo != null &&!mResCompatibilityInfo.supportsScreen()) {
3404 mResCompatibilityInfo.applyToConfiguration(mCompatConfiguration);
3405 config = mCompatConfiguration;
3406 }
3407 callbacks = collectComponentCallbacksLocked(false,config);
3408 }
3409
3410 if (callbacks != null) {
3411 final int N = callbacks.size();
3412 for (int i=0; i<N; i++) {
3413 performConfigurationChanged(callbacks.get(i),config);
3414 }
3415 }
3416 }
3213 ArrayList<ComponentCallbacks>collectComponentCallbacksLocked(
3214 boolean allActivities, Configuration newConfig) {
3215 ArrayList<ComponentCallbacks> callbacks
3216 = new ArrayList<ComponentCallbacks>();
3217
3218 if (mActivities.size() > 0) {
//对应activity情况
3219 Iterator<ActivityClientRecord> it =mActivities.values().iterator();
3220 while (it.hasNext()) {
3221 ActivityClientRecord ar = it.next();
3222 Activity a = ar.activity;
3223 if (a != null) {
3224 Configuration thisConfig =applyConfigCompatMainThread(newConfig,
3225 ar.packageInfo.mCompatibilityInfo.getIfNeeded());
3226 if (!ar.activity.mFinished &&(allActivities ||
3227 (a != null && !ar.paused))) {
3228 // If the activity is currently resumed,its configuration
3229 // needs to change right now.
3230
callbacks.add(a);
3231 } else if (thisConfig != null) {
3232 // Otherwise, we will tell it about thechange
3233 // the next time it is resumed or shown. Note that
3234 // the activity manager may, before then,decide the
3235 // activity needs to be destroyed tohandle its new
3239 ar.newConfig = thisConfig;
3240 }
3241 }
3242 }
3243 }
3244 if (mServices.size() > 0) {
//对应service情况
3245 Iterator<Service> it =mServices.values().iterator();
3246 while (it.hasNext()) {
3247
callbacks.add(it.next());
3248 }
3249 }
3250 synchronized (mProviderMap) {
3251 if (mLocalProviders.size() > 0) {
3252 Iterator<ProviderClientRecord> it =mLocalProviders.values().iterator();
3253 while (it.hasNext()) {
3254 callbacks.add(it.next().mLocalProvider);
3255 }
3256 }
3257 }
3258 final int N = mAllApplications.size();
3259 for (int i=0; i<N; i++) {
3260 callbacks.add(mAllApplications.get(i));
3261 }
3262
3263 return callbacks;
3264 }
Service,activity都会实现ComponentCallbacks接口
77public abstract class Service extends ContextWrapper implementsComponentCallbacks {
625public class Activity extends ContextThemeWrapper
626 implements LayoutInflater.Factory2,
627 Window.Callback, KeyEvent.Callback,
628 OnCreateContextMenuListener, ComponentCallbacks {
26public interface ComponentCallbacks {
39 void onConfigurationChanged(Configuration newConfig);
53 void onLowMemory();
54 }
附录:
如果用户想要Activity接受onConfigurationChanged事件而不relaunch,则需要进行如下修改
一:添加权限
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>
二:声明activity要捕获的事件类型,
<activity
android:configChanges="orientation|keyboard">