Android 7.0分屏原理及生命週期

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

參考資料 
示例 | Android Developers

轉自:http://blog.csdn.net/a279822581/article/details/52445154


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章