7.0分屏原理
7.0的Activity新增了onMultiWindowModeChanged方法,當頁面在分屏或不分屏狀態變換時,會回調這個方法。
分屏的任務管理器和虛擬按鍵在com/Android/systemui目錄下。長按多任務鍵時會調用PhoneStatusBar的toggleSplitScreenMode()方法。需要說明的是,多任務界面實際上是一個名叫RecentsActivity的Activity。
protected void toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) { if (mRecents == null) { return; } int dockSide = WindowManagerProxy.getInstance().getDockSide(); if (dockSide == WindowManager.DOCKED_INVALID) { //進入分屏模式,調出最近任務頁面。 mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, null, metricsDockAction); } else { EventBus.getDefault().send(new UndockingTaskEvent()); if (metricsUndockAction != -1) { MetricsLogger.action(mContext, metricsUndockAction); } }
需要分屏時會調用Recents的dockTopTask方法,該方法內部會調用RecentsImpl的dockTopTask,該方法除了在多任務界面做出任務管理“樣式”的調整以外,還會調用SystemServicesProxy.moveTaskToDockedStack,在分屏模式下打開最近任務
public void dockTopTask(int topTaskId, int dragMode, int stackCreateMode, Rect initialBounds) { SystemServicesProxy ssp = Recents.getSystemServices(); // Make sure we inform DividerView before we actually start the activity so we can change // the resize mode already. if (ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds)) {//遠程調用ActivityManagerService.moveTaskToDockedStack方法 EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds)); showRecents( false /* triggeredFromAltTab */, dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, false /* animate */, true /* launchedWhileDockingTask*/, false /* fromHome */, DividerView.INVALID_RECENTS_GROW_TARGET); }}
而該進程下的RecentsActivity則負責遠程與PackageManager通信,拿到應用截圖,添加到界面上
private void reloadStackView() { //省略部分代碼 RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options(); loadOpts.runningTaskId = launchState.launchedToTaskId; loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks; loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails; loader.loadTasks(this, loadPlan, loadOpts); TaskStack stack = loadPlan.getTaskStack(); mRecentsView.onReload(mIsVisible, stack.getTaskCount() == 0); mRecentsView.updateStack(stack, true /* setStackViewTasks */); // Update the nav bar scrim, but defer the animation until the enter-window event boolean animateNavBarScrim = !launchState.launchedViaDockGesture; mScrimViews.updateNavBarScrim(animateNavBarScrim, stack.getTaskCount() > 0, null); //省略部分代碼 }
那麼7.0的Activity新增的方法onMultiWindowModeChanged是在什麼時候調用的呢?回到剛纔的SystemServicesProxy.moveTaskToDockedStack,該方法會跨進程調用ActivityManagerService.moveTaskToDockedStack
public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate, Rect initialBounds, boolean moveHomeStackFront) { enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()"); synchronized (this) { long ident = Binder.clearCallingIdentity(); try { if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId + " to createMode=" + createMode + " toTop=" + toTop); mWindowManager.setDockedStackCreateState(createMode, initialBounds); final boolean moved = mStackSupervisor.moveTaskToStackLocked( taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, "moveTaskToDockedStack", animate, DEFER_RESUME); if (moved) { if (moveHomeStackFront) { mStackSupervisor.moveHomeStackToFront("moveTaskToDockedStack"); } mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } return moved; } finally { Binder.restoreCallingIdentity(ident); } } }
該方法會調用StackSupervisor.moveTaskToStackLocked,在StackSuperviso中做尺寸調整等工作以外,最終調用TaskRecord.updateOverrideConfiguration()。若需要分屏,則會調用scheduleReportMultiWindowModeChanged方法
Configuration updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) { //省略部分代碼 if (mFullscreen != oldFullscreen) { mService.mStackSupervisor.scheduleReportMultiWindowModeChanged(this); } return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null; }
scheduleReportMultiWindowModeChanged最終調用ActivityThreadhandleMultiWindowModeChanged,並通過appToken找到需要回調的Activity
private void handleMultiWindowModeChanged(IBinder token, boolean isInMultiWindowMode) { final ActivityClientRecord r = mActivities.get(token); if (r != null) { r.activity.dispatchMultiWindowModeChanged(isInMultiWindowMode); } }
Activity的dispatchMultiWindowModeChanged會回調onMultiWindowModeChanged,便可進行業務處理
分屏時Activity的生命週期
分三種情況
當前顯示自己的應用頁面,長按多任務鍵時出現分屏
onMultiWindowModeChanged(true)->onPause-onStop->onDestroy->onCreate->onStart- >onResume->onPause
分屏時長按多任務鍵,全屏顯示自己的應用時
onStop->onDestroy->onCreate->onStart->onResume>onPause>onMultiWindowModeChanged(false)->onResume
當前顯示其他應用,按多任務鍵出現自己的應用時
onMultiWindowModeChanged(true)->nDestroy->onCreate->onStart->onResume
轉自:http://blog.csdn.net/a279822581/article/details/52445154