深入理解WindowManager

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/asffghfgfghfg1556/article/details/81586509

WindowManager

  • 我们知道Window是通过WindowManager来管理的,而与WindowManager对应的还有一个WMS(WindowManagerService)那么他们两者到底是怎么工作的呢?接下来我们就来具体分许一下
  • 这篇文章我们重点分析WindowManager的基本知识脉络,而不去看具体的实现细节,我们只关心WindowManager和WindowManagerService(以下简称WMS),Surface,SurfaceFinger之间如何建立关联,以及交互的过程

  • Android系统中有很多个服务,这些服务在App执行的时候会将所用到的服务全都注册到一个Map当中(ContextImpl的register方法),当我们想使用某个服务的时候,就可以通过Context.getSystemService来获取服务
  • 那么WindowManager也是一种服务,在SystemServiceRegistry的静态区里面会对系统所用的一些服务进行注册,而WindowManager就是其中一种,我们来看看注册的具体操作
registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher<WindowManager>() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
                return new WindowManagerImpl(ctx);
            }});
  • 其中,前者我们应该挺熟悉,当我们想要得到某个服务的时候会这样调用
getSystemService(Context.WINDOW_SERVICE);
  • 所以,注册方法的内部实现其实是类似于Map,两个参数其实就是一个键值对,我们可以很容易通过Key得到Value
  • 好了,我们看到WindowManager服务其实是WindowManagerImpl的对象,我们去看一下这个类的实现
public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Context mContext;
    private final Window mParentWindow;

    private IBinder mDefaultToken;

    public WindowManagerImpl(Context context) {
        this(context, null);
    }

    private WindowManagerImpl(Context context, Window parentWindow) {
        mContext = context;
        mParentWindow = parentWindow;
    }

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }

    public WindowManagerImpl createPresentationWindowManager(Context displayContext) {
        return new WindowManagerImpl(displayContext, mParentWindow);
    }

    /**
     * Sets the window token to assign when none is specified by the client or
     * available from the parent window.
     *
     * @param token The default token to assign.
     */
    public void setDefaultToken(IBinder token) {
        mDefaultToken = token;
    }

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

    @Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.updateViewLayout(view, params);
    }

    private void applyDefaultToken(@NonNull ViewGroup.LayoutParams params) {
        // Only use the default token if we don't have a parent window.
        if (mDefaultToken != null && mParentWindow == null) {
            if (!(params instanceof WindowManager.LayoutParams)) {
                throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
            }

            // Only use the default token if we don't already have a token.
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
            if (wparams.token == null) {
                wparams.token = mDefaultToken;
            }
        }
    }

    @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

    @Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }

    @Override
    public void requestAppKeyboardShortcuts(
            final KeyboardShortcutsReceiver receiver, int deviceId) {
        IResultReceiver resultReceiver = new IResultReceiver.Stub() {
            @Override
            public void send(int resultCode, Bundle resultData) throws RemoteException {
                List<KeyboardShortcutGroup> result =
                        resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY);
                receiver.onKeyboardShortcutsReceived(result);
            }
        };
        try {
            WindowManagerGlobal.getWindowManagerService()
                .requestAppKeyboardShortcuts(resultReceiver, deviceId);
        } catch (RemoteException e) {
        }
    }

    @Override
    public Display getDefaultDisplay() {
        return mContext.getDisplay();
    }
}
  • 这个类并不长,我们可以很轻易的分析到这个类就是WindowManager操作Window的类,不过具体的实现细节还是由WindowManagerGlobal这个类来做的,这个类是一个单例模式
  • 那么管理Window的类找到了,他和Window之间的关系呢?我们在这里来看Dialog的实现吧,因为Dialog其实也是一个Window,并且它支持自定义布局,所以肯定会用到WIndowManager来管理Window,而且他的内容少,分析起来不是那么费劲
  • 我们先去看看Dialog的构造方法
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (themeResId == ResourceId.ID_NULL) {
                final TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
                themeResId = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, themeResId);
        } else {
            mContext = context;
        }

        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setOnWindowSwipeDismissedCallback(() -> {
            if (mCancelable) {
                cancel();
            }
        });
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);

        mListenersHandler = new ListenersHandler(this);
    }
  • 其中有这两句,我单独拿出来
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Window w = new PhoneWindow(mContext);
w.setWindowManager(mWindowManager, null, null);
  • 可见,我们在他的构造方法里面得到操作Window的WIndowManager,然后将WindowManager设置给Window,那个getSystemService方法就不看了,就是从前面所说的Map当中获取到那个WindowManagerImpl类实例,然后接下来我们看看setWindowManager这个方法,看看一个Window是如何和WindowManager建立联系,从而能让前者被后者管理,这个setWindowManager是Window的方法,我们点进去看看
public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
        setWindowManager(wm, appToken, appName, false);
    }

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
  • 所以,我们去看看WindowManagerImpl的createLocalWindowManager方法
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }
private WindowManagerImpl(Context context, Window parentWindow) {
        mContext = context;
        mParentWindow = parentWindow;
    }
  • 这里只不过是通过之前传进来的WindowManagerImpl实例又去创建了一个具有ParentWindow的WindowManagerImpl实例,根据他的参数可以看出,这里的Dialog本身的Window是作为WindowManagerImpl的parentWindow的,也就是他们俩的关系从表面看上去好像是父级和子级的层级关系
  • 那么关于这个parentWindow参数的意义,我们暂时先不管,带着这个问题继续看
  • 根据我们的推论,和对上面WindowManagerImpl这个类的代码的简单分析,我们不难得出,WindowManager对Window的操作主要来自于三个方面( addView,updateViewLayout,removeView),而我们也看到了,这三种方法的实现都是通过WindowManagerGlobal这个类来实现的,而这个类在调用addView的时候是传进了parentWindow这个参数,我们就去看看WindowManagerGlobal这个类对这三种方法的具体实现吧
  • 先看addView方法
public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
//省略前面的判空语句
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
        //这句话根据意思大概就能猜到是对上面的布局属性的限制,因为我们的布局是要添加到Window(这里指Dialog的,所以这里的布局属性要适应我们的Window)
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            // If there's no parent, then hardware acceleration for this view is
            // set from the application's hardware acceleration setting.
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // Start watching for system property changes.
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }

            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            // If this is a panel window, then find the window it is being
            // attached to for future reference.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }
//不看前面的判断,下面就是简单的构建View,和构建View的属性,并添加到WindowManagerGlobal管理Window的一些集合中
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            // do this last because it fires off messages to start doing things
            try {
            //将View显示到手机窗口
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }
  • 在上面方法的最后我们看到最终是通过root(ViewRootImpl类实例)的setView来显示到界面上面的,而ViewRootImpl并不是一个View,他是native层和FrameWork层通信的桥梁,比如我们熟悉的performTraversals函数收到系统绘制View的消息之后,通过调用视图树的各个节点的measure,layout,和draw方法来绘制整颗视图树
  • 而WindowManager是FrameWork层的,但是WMS运行在Native层的,而这两者之间的通信就是通过ViewRootImpl来做的,我们具体看看他是怎么做的
  • 在上个方法中先是构造出一个ViewRootImpl实例,所以我们先去看看他的构造方法
public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();

        mThread = Thread.currentThread();

    }
  • 其他东西我删掉了,在这里我们看到先是获取WindowSession,然后再得到了一个线程的引用,这个线程其实就是UI线程。
  • 这里的获取Session也就是与WMS建立连接,我们点进去接着看
public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }


public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    if (sWindowManagerService != null) {
                        ValueAnimator.setDurationScale(
                                sWindowManagerService.getCurrentAnimatorScale());
                    }
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowManagerService;
        }
    }
  • 在getWindowSession方法中,frameWork层先通过getWindowManagerService方法获取到IWindowManager对象,在getWindowManagerService方法发中,通过ServiceManager.getService(“window”)获取到WMS,点到ServiceManager.getService方法中
public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return Binder.allowBlocking(getIServiceManager().getService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
  • 可见该方法返回的是一个IBinder对象,然后通过IWindowManager.Stub.asInterface将他包装成一个相应进程的通信的对象(这里我也不知道怎么解释这个的好,不明白Binder机制的可以去看看我的这篇文章,Android-IPC机制探索
  • 最后通过 windowManager.openSession与WMS方法建立一个通信回话,相当于FrameWork层与Native层建立了一个长期合作的办事处,双方有什么需求都可以通过Session来交换信息,
  • 但是,,这个时候Dialog(或者说是Activity的View)并不能显示在手机屏幕上,WMS只是负责管理手机屏幕上的View的Z-Order(也就是View的显示层次,最上面的View层次当然能被人们所见,最下面的被上面的View覆盖,当然是不可见状态)
  • 这里看明白之后我们再回到前面的addView,他有一个ParentWindow参数,在前面的分析中,我们可以分析出,WMS管理的并非是Window,而是Window里面的View,这个不难理解
  • 然后我们接着看addView里面的ViewRootImpl的setView方法
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {

        requestLayout();

         try {
             mOrigWindowType = mWindowAttributes.type;
             mAttachInfo.mRecomputeGlobalAttributes = true;
             collectViewAttributes();
             res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                     getHostVisibility(), mDisplay.getDisplayId(),
                     mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                     mAttachInfo.mOutsets, mInputChannel);
         }

}
  • 这个方法很长,我将大部分东西都删掉,这里我们只关注这两个方法,先 requestLayout();然后在mWindowSession.addToDisplay,我们先看看第一个方法
public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
  • 我点到mHandler.getLooper().getQueue().postSyncBarrier()这个方法里面看了下,并没有找到我们想要的处理Traversal的东西,不过看下面这句代码mChoreographer.postCallback貌似有点名堂,先看看他的这个postCallback方法
public void postCallback(int callbackType, Runnable action, Object token) {
        postCallbackDelayed(callbackType, action, token, 0);
    }

public void postCallbackDelayed(int callbackType,
            Runnable action, Object token, long delayMillis) {
        if (action == null) {
            throw new IllegalArgumentException("action must not be null");
        }
        if (callbackType < 0 || callbackType > CALLBACK_LAST) {
            throw new IllegalArgumentException("callbackType is invalid");
        }

        postCallbackDelayedInternal(callbackType, action, token, delayMillis);
    }


private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        if (DEBUG_FRAMES) {
            Log.d(TAG, "PostCallback: type=" + callbackType
                    + ", action=" + action + ", token=" + token
                    + ", delayMillis=" + delayMillis);
        }

        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }
  • 最终会生成一个what值为MSG_DO_SCHEDULE_CALLBACK的Message,点到这个Handler的handleMessage方法里面找到这个参数的部分
public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_DO_FRAME:
                    doFrame(System.nanoTime(), 0);
                    break;
                case MSG_DO_SCHEDULE_VSYNC:
                    doScheduleVsync();
                    break;
                case MSG_DO_SCHEDULE_CALLBACK:
                    doScheduleCallback(msg.arg1);
                    break;
            }
        }
  • 执行的是doScheduleCallback(msg.arg1);这个方法,我们回过头再看看刚才给Msg设置的那个action值
  • 他在一开始是在这里传入的
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
  • 这里的mTraversalRunnable也就是我们那会传的action,看看这个mTraversalRunnable的实现
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }
  • 最终调用了performTraversals();,而这个方法的内容主要有四步:1. 获取Surface对象,用于图形的绘制,2. 丈量整个视图树的各个View的尺寸
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
  • 3.布局整个视图树,performLayout(lp, mWidth, mHeight);, 4.绘制整个视图树 performDraw();
  • 在第四步中,Framework会获取到图形绘制表面Surface对象,然后获取他的可绘制区域,也就是我们Canvas对象,然后开始绘制
private void performDraw() {
        if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
            return;
        } else if (mView == null) {
            return;
        }

        final boolean fullRedrawNeeded = mFullRedrawNeeded;
        mFullRedrawNeeded = false;

        mIsDrawing = true;
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
        try {
            draw(fullRedrawNeeded);
        } finally {
            mIsDrawing = false;
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
//其他代码删掉了
}
  • 然后调用 draw(fullRedrawNeeded);
 private void draw(boolean fullRedrawNeeded) {
 //获取绘制表面
        Surface surface = mSurface;
        if (!surface.isValid()) {
            return;
        }
        //其他代码删掉,这里是如果绘制表面需要更新
        if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
        //使用GPU绘制
            if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
                // If accessibility focus moved, always invalidate the root.
                boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
                mInvalidateRootRequested = false;

                // Draw with hardware renderer.
                mIsAnimating = false;

                if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
                    mHardwareYOffset = yOffset;
                    mHardwareXOffset = xOffset;
                    invalidateRoot = true;
                }

                if (invalidateRoot) {
                    mAttachInfo.mThreadedRenderer.invalidateRoot();
                }

                dirty.setEmpty();

                // Stage the content drawn size now. It will be transferred to the renderer
                // shortly before the draw commands get send to the renderer.
                final boolean updated = updateContentDrawBounds();

                if (mReportNextDraw) {
                    // report next draw overrides setStopped()
                    // This value is re-sync'd to the value of mStopped
                    // in the handling of mReportNextDraw post-draw.
                    mAttachInfo.mThreadedRenderer.setStopped(false);
                }

                if (updated) {
                    requestDrawWindow();
                }

                mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
            } else {

                if (mAttachInfo.mThreadedRenderer != null &&
                        !mAttachInfo.mThreadedRenderer.isEnabled() &&
                        mAttachInfo.mThreadedRenderer.isRequested()) {

                    try {
                        mAttachInfo.mThreadedRenderer.initializeIfNeeded(
                                mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
                    } catch (OutOfResourcesException e) {
                        handleOutOfResourcesException(e);
                        return;
                    }

                    mFullRedrawNeeded = true;
                    scheduleTraversals();
                    return;
                }
//使用cPU绘制
                if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
                    return;
                }
            }
        }

        if (animating) {
            mFullRedrawNeeded = true;
            scheduleTraversals();
        }
    }
  • 在draw方法中会获取到需要绘制的区域,一般我们使用的是CPU绘制,也就是drawSoftware方法
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
            boolean scalingRequired, Rect dirty) {

        // Draw with software renderer.
        final Canvas canvas;
        try {
            final int left = dirty.left;
            final int top = dirty.top;
            final int right = dirty.right;
            final int bottom = dirty.bottom;
//获取指定区域的canvas对象,用于FrameWork层绘图
            canvas = mSurface.lockCanvas(dirty);

            // The dirty rectangle can be modified by Surface.lockCanvas()
            //noinspection ConstantConditions
            if (left != dirty.left || top != dirty.top || right != dirty.right
                    || bottom != dirty.bottom) {
                attachInfo.mIgnoreDirtyState = true;
            }

            // TODO: Do this in native
            canvas.setDensity(mDensity);
        } 

        try {
            if (DEBUG_ORIENTATION || DEBUG_DRAW) {
                Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
                        + canvas.getWidth() + ", h=" + canvas.getHeight());
                //canvas.drawARGB(255, 255, 0, 0);
            }

            dirty.setEmpty();
            mIsAnimating = false;
            mView.mPrivateFlags |= View.PFLAG_DRAWN;

            try {
                canvas.translate(-xoff, -yoff);
                if (mTranslator != null) {
                    mTranslator.translateCanvas(canvas);
                }
                canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
                attachInfo.mSetIgnoreDirtyState = false;
//从DecorView开始绘制,也就是整个Window的根视图,这会引起整棵树的重绘
                mView.draw(canvas);

                drawAccessibilityFocusedDrawableIfNeeded(canvas);
            } 
        } finally {
            try {
            //释放canvas锁,然后通知SurfaceFlinger更新这片区域
                surface.unlockCanvasAndPost(canvas);
            } catch (IllegalArgumentException e) {
                Log.e(mTag, "Could not unlock surface", e);
                mLayoutRequested = true;    // ask wm for a new surface next time.
                //noinspection ReturnInsideFinallyBlock
                return false;
            }

            if (LOCAL_LOGV) {
                Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
            }
        }
        return true;
    }
  • 整个流程在代码中已经注释清楚,在绘制完成之后请求WMS显示该窗口的内容
  • 最后来张图
    这里写图片描述

猜你喜欢

转载自blog.csdn.net/asffghfgfghfg1556/article/details/81586509
今日推荐