美文网首页
android view window

android view window

作者: couriravant | 来源:发表于2021-04-12 20:09 被阅读0次

    两个情况,一个是DecorView,也就是activity的创建,另一种就是直接window添加view,如dialog等

    Activity的启动中会有:

    1。performLaunchActivity()主要做了以下几件事:

    创建Activity。

    创建Context。

    调用Activity.attach(),创建Window,关联WindowManager。

    调用Activity.onCreate()。

    调用Activity.onStart()。

    2.handleResumeActivity()处理的事情比较多。我总结为以下几个过程:

    通过performResumeActivity()处理Activity的onRestart onResume的生命周期。

    将DecorView设置为InVisible。

    通过WindowManager.addView()将DecorView绘制完成。

    将DecorView设置为Visiable。

    通知AMS Activity启动完成。

    
    
    

    WindowManager直接添加view的例子:

    //1. 控件
            Button button = new Button(this);
            button.setText("Window Button");
            //2. 布局参数
            WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT);
            layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
            layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
            layoutParams.x = 100;
            layoutParams.y = 300;
            // 必须要有type不然会异常: the specified window type 0 is not valid
            layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
            //3. 获取WindowManager并添加控件到Window中
            WindowManager windowManager = getWindowManager();
            windowManager.addView(button, layoutParams);
    

    WindowManagerGlobal

    public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
    ...
    //新建ViewRootImpl
      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 {
                //调用ViewRootImpl的setview
                    root.setView(view, wparams, panelParentView);
                } catch (RuntimeException e) {
                    // BadTokenException or InvalidDisplayException, clean up.
                    if (index >= 0) {
                        removeViewLocked(index, true);
                    }
                    throw e;
                }
            }
        } 
    

    ViewRootImpl

     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    。。。
    requestLayout();
    。。
     try {
                        mOrigWindowType = mWindowAttributes.type;
                        mAttachInfo.mRecomputeGlobalAttributes = true;
                        collectViewAttributes();
    //windowsession 
                        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
                    } catch (RemoteException e) {}
    }
    
    
    
    
    
     @Override
        public void requestLayout() {
            if (!mHandlingLayoutInLayoutRequest) {
                checkThread();
                mLayoutRequested = true;
                scheduleTraversals();
            }
        }
    
    
     void scheduleTraversals() {
            if (!mTraversalScheduled) {
                mTraversalScheduled = true;
                mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
    //1. 实际是View绘制的入口(测量、布局、重绘)--内部通过mChoreographer去监听下一帧的刷新信号
                mChoreographer.postCallback(
                        Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
                if (!mUnbufferedInputDispatch) {
                    scheduleConsumeBatchedInput();
                }
                notifyRendererOfFramePending();
                pokeDrawLockIfNeeded();
            }
        }
    
    
    
    final class TraversalRunnable implements Runnable {
            @Override
            public void run() {
                doTraversal();
            }
        }
    
    
     //Session.java
        @Override
        public int addToDisplay(IWindow window, ...) {
            return mService.addWindow(this, window, ...);
        }
    
        //WindowManagerService.java
        public int addWindow(Session session, IWindow client, ...) {
            /**=================================
             * 1. 检查工作
             *    1-权限检查和设置相关
             *    2-检查是否重复添加---Binder对象会存储在HashMap<IBinder, WindowState>中
             *=================================*/
            ...
            if (mWindowMap.containsKey(client.asBinder())) {
                ...
            }
            // 2. 返回WmS中存在的对应父窗口,若不存在则返回null
            WindowState attachedWindow = windowForClientLocked(null, attrs.token, false);
            ...
            /**===========================================
             * 3. 从WmS中寻找对应的WindowToken, 并且处理合法性
             *   1-例如:对于子窗口来说,WmS中必须有对应的Token才能添加
             *   2-例如:token不为null且是应用窗口是必须要有个windowToken
     *============================================*/
            WindowToken token = mTokenMap.get(attrs.token);
            /**
             * ...检查Token合法性...
             */
            // 4. 创建窗口
            WindowState win = new WindowState(session, client, token, attachedWindow, attrs, viewVisibility);
            /**==============================================
             * 5. 额外的操作、信息保存等
             *      1. 如果是Toast,则此窗口不能够接收input事件
             *      2. Token添加到WmS中
             *      3. 窗口信息添加到WmS中
             *      4. 将窗口(WindowState)添加到Session中
             *      5. 对于应用启动时显示的窗口,设置token
             *==============================================*/
            // 1、如果是Toast,则此窗口不能够接收input事件
            mPolicy.adjustWindowParamsLw(win.mAttrs);
            // 2、从上述代码中得出是否要添加Token,若是则添加Token添加到WmS中
            if (addToken) {
                mTokenMap.put(attrs.token, token);
                mTokenList.add(token);
            }
            // 3、窗口信息添加到WmS中
            mWindowMap.put(client.asBinder(), win);
            // 4、将窗口添加到Session中
            win.attach();
            // 5、对于应用启动时显示的窗口,设置token
            token.appWindowToken.startingWindow = win;
            ...
        }
    

    接着会通过WindowSession最终来完成Window的添加过程。在下面的代码中mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是说这其实是一次IPC过程,远程调用了Session中的addToDisPlay方法。

    refer:https://blog.csdn.net/cpcpcp123/article/details/115266556

    refer: https://blog.csdn.net/feather_wch/article/details/81437056

    refer:https://mp.weixin.qq.com/s?__biz=MzU4NDc1MjI4Mw==&mid=2247483864&idx=1&sn=ca212f527ed4d29e1910d689f2f69b0e&chksm=fd944c2ccae3c53a36432164917d8c1d7d447204e036dd08ffb3d7fea43526ecdc8df87d0668&token=917258391&lang=zh_CN&scene=21#wechat_redirect

    相关文章

      网友评论

          本文标题:android view window

          本文链接:https://www.haomeiwen.com/subject/qdhoehtx.html