现在的位置: 首页 > 综合 > 正文

Andorid Configuration机制分析

2013年01月27日 ⁄ 综合 ⁄ 共 10534字 ⁄ 字号 评论关闭

       Andorid 系统中configuration是一个很重要的模块,我们旋转屏幕,低电量等系统配置变化时就会激发configuration改变的事件,configurationChanged事件会导致两种效果,对于不支持onConfigurationChanged事件的Activity,则relauncher它,否则直接调用它的onConfigurationChanged

      Configuration更新主要有两个源,一个是当我们旋转屏幕时,还有一个是每当有新的Activityresumed时会更新Configuration,如果Configuration有改变就会通知系统各个单元Configuration改变了,目标主要是ActivityService.

激发点一: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检测,如果startingdetroy,则其他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 }

Serviceactivity都会实现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">

抱歉!评论已关闭.