• android Window WindowManager 整理


    Android可以直接可见的界面包括Activity Toast Dialog  PopuWindow ...

    android的窗口分为三种:

    1、应用程序窗口 (Application Window): 包括所有应用程序自己创建的窗口,以及在应用起来之前系统负责显示的窗口。

    2、子窗口(Sub Window):比如应用自定义的对话框,或者输入法窗口,子窗口必须依附于某个应用窗口(设置相同的token)。

    3、系统窗口(System Window): 系统设计的,不依附于任何应用的窗口,比如说,状态栏(Status Bar), 导航栏(Navigation Bar), 壁纸(Wallpaper), 来电显示窗口(Phone),锁屏窗口(KeyGuard), 信息提示窗口(Toast), 音量调整窗口,鼠标光标等等。

    1、Windowandroid中的窗口,表示顶级窗口的意思,也就是主窗口,它有两个实现类,PhoneWindowMidWindow

         (1)  我们一般的activity对应的主要是PhoneWindow,在activity中经常使用的setContentView等方法也是在这个里面实现的。

             performLaunchActivity中,会调用activity.attach方法建立一个window, 在handleResumeActivity方法中启动activity的时候,会将主窗口加入到WindowManager中

         (2) popupwindow是属于 sub window的,所以一定要有一个view去依附

         (3) 自定义Toast:自定义的原理也很简单,就是给WindowManager添加View和删除View,不过需要设置WindowManager.LayoutParams和View的样式,使其看起来和Android系统的Toast看起来很相像。

            Toast是通过WindowManager调用addView加载进来的。因此,hide方法自然是WindowManager调用removeView方法来将Toast视图移除。 总结一下,通过对TN类的源码分析,我们知道了TN类是回调对象,其他进程调用tn类的show和hide方法         来控制这个Toast的显示和消失。Toast类的show方法中,我们可以看到,这里调用了getService得到INotificationManager服务,判断是否为系统Toast。

             1) 如果当前Toast所属的进程的包名为“android”,则为系统Toast,否则还可以调用isCallerSystem()方法来;

              判断当前Toast所属进程的uid是否为SYSTEM_UID、0、PHONE_UID中的一个,如果是,则为系统Toast;如果不是,则不为系统Toast。 是否为系统Toast,通过下面的源码阅读可知,主要有两点优势: 系统Toast一定可以进入到系统Toast           队列中,不会被黑名单阻止。系统Toast在系统Toast队列中没有数量限制,而普通pkg所发送的Toast在系统Toast队列中有数量限制。

             2) 查看将要入队的Toast是否已经在系统Toast队列中。这是通过比对pkg和callback来实现的

             3) 将当前Toast所在进程设置为前台进程,这里的mAm=ActivityManagerNative.getDefault(),调用了setProcessForeground方法将当前pid的进程置为前台进程,保证不会系统杀死。这也就解释了为什么当我们finish当前Activity时,             Toast还可以显示,因为当前进程还在执行。

                4)   index为0时,对队列头的Toast进行显示
    (4) Dialog
          在service中打开dialog需要编程系统窗口

            改变Dialog背景透明度:

            Dialog dg = new Dialog(this); 

            Window window = dg.getWindow(); 

            WindowManager.LayoutParams lp = window.getAttributes(); 

            lp.alpha = 0.5f; 

            window.setAttributes(lp);

    WindowManager:

    WindowManager主要用来管理窗口的一些状态、属性、view增加、删除、更新、窗口顺序、消息收集和处理等。

    通过Context.getSystemService(Context.WINDOW_SERVICE)的方式可以获得WindowManager的实例.

    WindowManager继承自ViewManager,里面涉及到窗口管理的三个重要方法,分别是:

         * addView(); 

         * updateViewLayout();

         * removeView();  

    WindowManager中还有一个重要的静态类LayoutParams.通过它可以设置和获得当前窗口的一些属性。

    我们先来看看addView()方法,在addView中,会利用LayoutParams获得window的View属性,并为每个window创建ViewRoot,ViewRoot是View和WindowManager之间的桥梁,真正把View传递给WindowManager的是通过ViewRoot的setView()方法,ViewRoot实现了View和WindowManager之间的消息传递。在将主窗口添加到WindowManger时,它首先会建立一个代理对象:

                  wm=(WindowManagerImpl)context.getSystemService(Context.WINDOW_SERVICE)

    并且打开会话(IWindowSession),之后Window将通过该会话与WindowManager建立联系,

    来看下setView方法:

             try {

            res =sWindowSession.add(mWindow, mWindowAttributes,

             getHostVisibility(), mAttachInfo.mContentInsets);

         } catch (RemoteException e) {

             mAdded = false;

            mView = null;

             mAttachInfo.mRootView =null;

             unscheduleTraversals();

             throw newRuntimeException("Adding window failed", e);

          } finally {

             if (restore) {

                attrs.restore();

             }

          }

    在这段代码中,ViewRoot通过IWindowSession把窗口添加到WindowManager中。ViewRoot继承了Handler,实际上它的本质就是一个Handler,窗口中View的事件处理、消息发送、回调等将通过ViewRoot来处理。

    这样就完成了把窗口添加到WindowManager中,并交由WindowManager来管理窗口的view、事件、消息收集处理等。

     更新UI的线程必须是添加window的线程

    在初始化一个ViewRootImpl函数的时候,会调用native方法,获取到该线程对象mThread,接着setText函数会调用到requestLayout方法

    (TextView绘制出来之后,调用setText才会去调用requestLayout方法,没有绘制出来之前,在子线程中调用setText是不会抛出Exception):

    public void requestLayout() {
        .....
        checkThread();
        .....
    }
    ....
    void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

    在android中真正展示给用户的是window和view,activity在android中所其的作用主要是处理一些逻辑问题,比如生命周期的管理、建立窗口等。

    android中,窗口的管理还是比较重要的一块,因为他直接负责把内容展示给用户,并和用户进行交互。响应用户的输入等。

    先说下ViewManager这个接口,这个接口主要有以下的实现子接口和实现类,分别是:WindowManager和ViewGroup里面还有三个重要的方法:

          * addView(); 

         * updateViewLayout();

         * removeView();

    在WindowManager中,addView方法表示的是将主窗口中的顶级view(也就是DecorView)添加到WindowManager中,并建立会话。接下来会详细介绍。我们先来看看Window

    Window:

    Windowandroid中的窗口,表示顶级窗口的意思,也就是主窗口,它有两个实现类,PhoneWindowMidWindow,

    我们一般的activity对应的主要是PhoneWindow,在activity中经常使用的setContentView等方法也是在这个里面实现的。

        @Override

        public void setContentView(View view,ViewGroup.LayoutParams params) {

            if (mContentParent == null) {

                installDecor();

            } else {

                mContentParent.removeAllViews();

            }

            mContentParent.addView(view, params);

            final Callback cb = getCallback();

            if (cb != null) {

               cb.onContentChanged();  //窗口类容发生变化时更新

            }

        }

     每个主窗口中都有一个View,称之为DecorView,是主窗口中的顶级view(实际上就是ViewGroup),在View中有两个成员变量叫做mParent、mChildren,它是用来管理view的上下级关系的。

    而ViewGroup是对一组View的管理。因此,在ViewGroup中建立了所有view的关系网。而最终ViewGroup附属在主窗口上。这样就很容易在窗口中通过findViewById找到具体的View了。view中的事件处理也是根据这个路径来处理的。

    我们再来看看ActivityThead中的两个重要的方法(至于ActivityThead将在一篇中详细介绍):

               performLaunchActivity( );

                handleResumeActivity( );

    在performLaunchActivity中,会调用activity.attach方法建立一个window, 在handleResumeActivity方法中启动activity的时候,会将主窗口加入到WindowManager中

                 View decor =r.window.getDecorView();  //获得窗口的顶级View

          decor.setVisibility(View.INVISIBLE);

          ViewManager wm= a.getWindowManager();    //WindowManager继承自ViewManager

          WindowManager.LayoutParams l =r.window.getAttributes();

          a.mDecor = decor;

          l.type =WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

         l.softInputMode |= forwardBit;

         if (a.mVisibleFromClient) {

             a.mWindowAdded = true;

             wm.addView(decor, l);  //实际上是把主窗口的顶级view加入到WindowMangaer

          }

    我们再来看看WindowManager。

    WindowManager:

    WindowManager主要用来管理窗口的一些状态、属性、view增加、删除、更新、窗口顺序、消息收集和处理等。

    通过Context.getSystemService(Context.WINDOW_SERVICE)的方式可以获得WindowManager的实例.

    WindowManager继承自ViewManager,里面涉及到窗口管理的三个重要方法,分别是:

         * addView(); 

         * updateViewLayout();

         * removeView();  

    WindowManager中还有一个重要的静态类LayoutParams.通过它可以设置和获得当前窗口的一些属性。

    我们先来看看addView()方法,在addView中,会利用LayoutParams获得window的View属性,并为每个window创建ViewRoot,

    ViewRoot是View和WindowManager之间的桥梁,真正把View传递给WindowManager的是通过ViewRoot的setView()方法,

    ViewRoot实现了View和WindowManager之间的消息传递。在将主窗口添加到WindowManger时,它首先会建立一个代理对象:

                  wm=(WindowManagerImpl)context.getSystemService(Context.WINDOW_SERVICE)

    并且打开会话(IWindowSession),之后Window将通过该会话与WindowManager建立联系,

    来看下setView方法:

             try {

            res =sWindowSession.add(mWindow, mWindowAttributes,

             getHostVisibility(), mAttachInfo.mContentInsets);

         } catch (RemoteException e) {

             mAdded = false;

            mView = null;

             mAttachInfo.mRootView =null;

             unscheduleTraversals();

             throw newRuntimeException("Adding window failed", e);

          } finally {

             if (restore) {

                attrs.restore();

             }

          }

    在这段代码中,ViewRoot通过IWindowSession把窗口添加到WindowManager中。ViewRoot继承了Handler,实际上它的本质就是一个Handler,窗口中View的事件处理、消息发送、回调等将通过ViewRoot来处理。

    这样就完成了把窗口添加到WindowManager中,并交由WindowManager来管理窗口的view、事件、消息收集处理等。

  • 相关阅读:
    Android虚拟、实体键盘不能同时使用?
    libwebsockets 运行问题
    Qt TabWidget QTabBar 宽高设置
    I.MX6 recovery mode hacking
    libwebsockets libwebsockets-webserver.c hacking
    MySQL(六)常用语法和数据类型
    MySQL(五)汇总和分组数据
    MySQL(四)字段及常用函数
    MySQL(三)用正则表达式搜索
    MySQL(二)数据的检索和过滤
  • 原文地址:https://www.cnblogs.com/xunzhi/p/5671337.html
Copyright © 2020-2023  润新知