《Android开发艺术探索》学习笔记-Window

WindowManager

获取方式:

context.getSystemService(Context.WINDOW_SERVICE)

自由添加一个window层的控件:

val layoutParams = WindowManager.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT, TYPE_APPLICATION_OVERLAY, 0,
            PixelFormat.TRANSPARENT
        )
        layoutParams.flags =
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                    WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
        layoutParams.gravity = Gravity.LEFT or Gravity.TOP
        layoutParams.x = 100
        layoutParams.x = 300

        val view = TextView(context)
        view.text = "WindowManager test"
        val windowManager: WindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        windowManager.addView(view,layoutParams)

window实际是以View的形式存在的,WindowManager添加View时会创建对应的window被View依附

  • WindowManager继承自ViewManager
public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

是一组抽象方法,ViewGroup也实现自这个接口

  • WindowManager的实现类是WindowManagerImpl
  • WindowManagerImpl的方法实现实际上是操作WindowManagerGlobal,WindowManagerGlobal是单例
  • addView时,创建对应的ViewRootImpl,WindowManagerImpl中维护:
    mViews存放View对象;
    mRoots存放View对应的ViewRootImpl对象;
    addView的mParentWindow来源于createLocalWindowManager,通过createLocalWindowManager设置parentWindow(后面会说到设置所有依附于Activity的window的parentWindow都是Activity的window),Activity中获取的WindowManage都是绑定了PhoneWindow的
  if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);

mParams存放添加这个View时的WindowManager.LayoutParams

  • 最后交给了ViewRootImpl.setView方法去添加
  • setView方法去添加
 requestLayout();
 ...
  res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
                            mTempInsets);
                    setFrame(mTmpFrame);

IWindowSession mWindowSession的实现是Session类,这里是个IPC,是通过WindowManagerService的openSession创建出来的,最后将任务交给了WindowManagerService的addWindow方法

  • mWindow是ViewRootImpl构造方法创建的,是个IWindow.Stub,也是用了IPC

Activity的Window

在Activity的attach方法中创建:

 mWindow = new PhoneWindow(this, window, activityConfigCallback);
 mWindow.setWindowControllerCallback(this);

所以Activity中的window就是PhoneWindow,并且设置了WindowControllerCallback就是Activity自己,Activity中的一些回调就来自这个window

Activity的setContentView方法

调用了window的setContentView

 getWindow().setContentView(layoutResID);

然后看PhoneWindow:

   public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

       。。。
       mLayoutInflater.inflate(layoutResID, mContentParent);
        。。。
    }
  1. 首先检查是否有mContentParent(setContentView方法可能会重复调用覆盖原有布局,所以这里需要判断),没有则:通过installDecor()先创建DecorView(#generateDecor(),同时会绑定当前Window),然后根据主题设置加载布局作为DecorView的子View(#generateLayout()),比如有标题栏则可能是个LinearLayout,将这个子View中id为content的View赋值给mContentParent。
  2. 最后将setContentView设置的View加载到mContentParent下面去
  3. 现在布局就加载到Window里DecorView下面mContentParent中去了,根据上面WindowManager的知识,最后需要WindowManager.addView才能完成View的添加
  4. 最后在Activity的makeVisible()方法中完成这件事
  void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

Dialog中的Window

总体和Activity相似。有一点不同就是openOptionsMenu()添加的window的parentWindow是Dialog的这个window(下面一条会说明parentWindow一般都是Activity的window),这样当弹窗消息时,依附弹窗的菜单方便一起管理

Context.getSystemService(Context.WINDOW_SERVICE)

我们添加的子window都是需要依附一个Activity,除非是系统级的,所以我们通过Context.getSystemService(Context.WINDOW_SERVICE)拿到的WindowManager本质上都是从Activity的getSystemService获取到的,Activity的mWindowManager是通过内部的mWindow获取到的,也就是createLocalWindowManager绑定了当前Activity持有的Window的,所以后续创建的window都是依附于当前Activity的Window的子window,即获取到的WindowManager的parentWindow都是Activty的这个window

待解决的问题

Activity里面创建的window以及Dialog中创建出来的window如何被加载的,即在WindowManager.addView的哪个过程被用到,区别于我们在一开始的例子:parentWindow上添加window的时候都是直接addView而用不自己创建window

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

推荐阅读更多精彩内容