美文网首页
笔记:window与windowManager

笔记:window与windowManager

作者: jiaming_ | 来源:发表于2017-10-23 09:39 被阅读61次

    window与windowManager


    • window在日常开发中如悬浮窗,它的实现是phoneWindow

    • window的创建通过WindowManager,WindowManager是外界访问window的入口。

    windowManager获取:

          WindowManager      wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    

    window通过setWindowManager()方法关联WindowManager


    • window的具体实现位于WindowManagerService,WindowManager和WindowManagerService的交互是一个IPC过程

    • Android所有的视图都是通过Window来呈现的,不管是Activity,Dialog,还是Toast,它们的视图实际上都是附加在Window上,因此,Window实际是View的实际管理者,

    • Activity设置视图的方法setContentView()底层也是通过Window来实现的

    • Window有3种类型
    1. 应用类window 对应一个Activity (1~99)
    2. 子window 不能单独存在,需要依附在特定的父window之中,比如Dialog (1000~1999)
    3. 系统window 需要声明权限才能创建的window,比如toast,系统状态栏 (2000~2999)

    • Window是分层的,每个Window都有对应的z-ordered,层级大的会覆盖在层级小的上面,和html的z-index概念完全一致*

    层级分别是上面的范围,对应着WindowManager.LayoutParams.type参数,想要覆盖在最上面,设置层级范围最大即可,即系统层级,一般选用:

    TYPE_SYSTEM_OVERLAY

    TYPE_SYSTEM_ERROR

    mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR
    同时声明权限

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    

    • WindowManage仅提供了三个方法,供开发者继承使用:
    public interface ViewManager{
        public void addView(View view, ViewGroup.LayoutParams params);
        public void updateViewLayout(View view, ViewGroup.LayoutParams params);
        public void removeView(View view);
    }
    

    • WindowManager实现类是WindowManagerImpl

    WindowManagerImpl并没有直接实现Window的三大操作,而是全部交给WindowManagerGlobal来处理,WindowManagerGlobal以工厂的形式向外提供实例-----典型的桥接模式


    Activity Window创建流程

    • Activity的Window的创建在attach()方法里完成的,在attach()方法里,系统会创建Activity所属的Window对象并为其设置回调接口,Window对象的创建是通过PolicyManager的makeNewWindow方法实现的

    由于Activity实现了Window的CallBack接口,因此Window接受到外界的回调就会回调到Activity中的方法,如onAttachToWindow(),onDetachFromWindow(),dispatchTouchEvent()

    PolicyManager 一个策略类,PolicyManager中实现的几个工厂方法全部在策略接口IPolicy中声明了,其中makeNewWindow()方法中完成new PhoneWindow()。

    (25版本中源码Activity的attch方法中直接new PhoneWindow(),并没有工厂模式)


    • Activity视图怎么依附到Window上的

    通过setContentView()来实现依附,setContent具体实现:

    1. 如果没有DecorView,就创建它
    2. 将View添加到DecorView的mContentParent中
    3. 回调Activity的onContentChanged()方法通知Activity的视图已经发生了改变

    在ActivityThread中的handleResumeActivity方法中,首先会调用onResume方法,然后再调用Activity的makeVivible()方法,正是在makeVisible()方法中,DecorView真正完成了显示和添加这两个过程到这里Activity才被用户看到。

    //Activity.java
        void makeVisible() {
            if (!mWindowAdded) {
                ViewManager wm = getWindowManager();
                wm.addView(mDecor, getWindow().getAttributes());
                mWindowAdded = true;
            }
            mDecor.setVisibility(View.VISIBLE);
        }
    

    Dialog Window创建流程


    • Dialog使用的是PhoneWindow,同样低版本使用了PlicyManager的makeNewWindow方法来完成,高版本直接new PhoneWindow();参考源码

    • 创建步骤
    1. 创建Window
    2. 初始化DecorView,并将Dialog视图添加到DecorView中

    setContentView()

    1. 将DecorView添加到Window中并显示
      在Dialog的show()方法中,通过WindowManager将DecorView添加到Window中,

       mWindowManager.addView(mDecor, l);
       mShowing = true;
      

    • 普通Dialog的Context必须使用Activity的Context,如果使用ApplicationContext,会报错。普通Dialog需要依附一个Window

    Toast的Window创建过程


    • Toast 内部有两类IPC通信过程
    1. Toast访问NotificationManagerService
    2. NotificationManagerService回调TN里的接口

    • TN是一个Binder类,用于NMS跨进程调用TN的方法,如hide(),show()

    所有TN里的hide,show()等方法都运行在Binder线程池中,所以需要Handle切换到当前线程中去。

    注意是切换到当前线程中。在没有Looper的线程中,Toast无法正确运行。


    • Toast的show()方法
        public void show() {
            if (mNextView == null) {
                throw new RuntimeException("setView must have been called");
            }
    
            INotificationManager service = getService();
            String pkg = mContext.getOpPackageName();
            TN tn = mTN;
            tn.mNextView = mNextView;
    
            try {
                service.enqueueToast(pkg, tn, mDuration);
            } catch (RemoteException e) {
                // Empty
            }
        }
    

    enqueueToast首先将Toast封装成ToastRecord对象,并将其添加到mToastQueue队列中,mToastQueue其实是一个ArrayList,对于非系统应用来说,该list长度最多为50个ToastRecord,这么做是为了防止DOS(拒绝服务攻击),也就是如果大量循环弹toast那么其他应用就无法弹了。


    • Toast 原理也就是Binder通信,Toast调用Show方法,内部会将该toast与TN传递给运行于系统进程的NMS中,由系统进程控制TN的show方法,系统需要统一管理toast,NMS会将该toast放入一个ArrayList执行队列中,while循环轮到该条toast时,取出该toast对于的TN对象,再通过Binder通信,执行远程TN对象的show方法,show方法会通过Handle让show过程脱离Binder线程池,运行于Looper线程中,show中实际通过WindowManage的addView方法,将View添加到window上。这样就完成了一次Toast显示过程,hide过程一样。

    相关文章

      网友评论

          本文标题:笔记:window与windowManager

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