笔记:window与windowManager

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过程一样。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容