美文网首页Android源码解析android源码分析
Android源码解析Window系列第(一)篇---Windo

Android源码解析Window系列第(一)篇---Windo

作者: LooperJing | 来源:发表于2016-12-12 01:28 被阅读1757次

    转载请注明文章出处LooperJing

    您可能听说过View ,ViewManager,Window,PhoneWindow,WindowManager,WindowManagerService,可是你知道这几个类是什么关系,干嘛用的。概括的来说,View是放在Window中的,Window是一个抽象类,它的具体实现是PhoneWindow,PhoneWindow还有个内部类DecorView,WindowManager是一个interface,继承自ViewManager,它是外界访问Window的入口,,提供了add/remove/updata的方法操作View,WindowManager与WindowManagerSerice是个跨进程的过程,WindowManagerService的职责是对系统中的所有窗口进行管理。如果您不太清楚,建议往下看,否则就不要看了。

    1、Window的类型

    Android系统的Window有很多种,大体上来说,Framework定义了三种窗口类型;

    • 系统Window
      常见的系统Window有哪些呢?比如在手机电量低的时候,会有一个提示电量低的Window,我们输入文字的时候,会弹出输入法Window,还有搜索条Window,来电显示Window,Toast对应的Window,可以总结出来,系统Window是独立与我们的应用程序的,对于应用程序而言,我们理论上是无法创建系统Window,因为没有权限,这个权限只有系统进程有。

    • 应用程序Window
      所谓应用窗口指的就是该窗口对应一个Activity,因此,要创建应用窗口就必须在Activity中完成了。本节后面会分析Activity对应的Window的创建过程。

    • 子Window
      所谓的子Window,是说这个Window必须要有一个父窗体,比如PopWindow,Dialog因为有自己的WindowToken,属于应用程序Window,这个比较特殊。

    这就是Framework定义了三种窗口类型,这三种类型定义在WindowManager的内部类LayoutParams中,WindowManager讲这三种类型 进行了细化,把每一种类型都用一个int常量来表示,这些常量代表窗口所在的层,WindowManagerService在进行窗口叠加的时候,会按照常量的大小分配不同的层,常量值越大,代表位置越靠上面,所以我们可以猜想一下,应用程序Window的层值常量要小于子Window的层值常量,子Window的层值常量要小于系统Window的层值常量。Window的层级关系如下所示。

    Android系统Window层级
    实际上应用程序的Window的层级范围是199,子Window的层级范围是10001999,系统Window的层级范围是2000~2999,这些值对应着WindowManager.LayoutParams的type参数,如果我们想窗口处在上面,那么只要采用层级比较大的type就行了。OK,到此我们对Window有了一个初步的认识。

    2、怎么去描述一个Window

    上面说了Window分为三种,用Window的type区分,在搞清楚Window的创建之前,我们需要知道怎么去描述一个Window,我们就把Window当做一个实体类,给我的感觉,它必须要下面几个字段。

    width:描述窗口的宽度
    height:描述窗口的高度
    type:这是哪一种类型的Window
    

    实际上WindowManager.LayoutParams对Window有很详细的定义。

    public interface WindowManager extends ViewManager {
        ...........
        public static class LayoutParams extends ViewGroup.LayoutParams
                implements Parcelable {
    
            //窗口的起点坐标
            public int x;
            public int y;
    
            //以下定义都是描述窗口的类型
            public int type;
            //第一个应用窗口
            public static final int FIRST_APPLICATION_WINDOW = 1;
            //所有程序窗口的base窗口,其他应用程序窗口都显示在它上面
            public static final int TYPE_BASE_APPLICATION   = 1;
            //所有Activity的窗口
            public static final int TYPE_APPLICATION        = 2;
            //目标应用窗口未启动之前的那个窗口
            public static final int TYPE_APPLICATION_STARTING = 3;
            //最后一个应用窗口
            public static final int LAST_APPLICATION_WINDOW = 99;
    
            //第一个子窗口
            public static final int FIRST_SUB_WINDOW        = 1000;
            // 面板窗口,显示于宿主窗口的上层
            public static final int TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW;
            // 媒体窗口(例如视频),显示于宿主窗口下层
            public static final int TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1;
            // 应用程序窗口的子面板,显示于所有面板窗口的上层
            public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2;
            //对话框窗口
            public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3;
            //
            public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW+4;
            //最后一个子窗口
            public static final int LAST_SUB_WINDOW         = 1999;
    
            //系统窗口,非应用程序创建
            public static final int FIRST_SYSTEM_WINDOW     = 2000;
            //状态栏,只能有一个状态栏,位于屏幕顶端,其他窗口都位于它下方
            public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
            //搜索栏,只能有一个搜索栏,位于屏幕上方
            public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;
            //电话窗口,它用于电话交互(特别是呼入),置于所有应用程序之上,状态栏之下
            public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
            //系统警告提示窗口,出现在应用程序窗口之上
            public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
            //锁屏窗口
            public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
            //信息窗口,用于显示Toast
            public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;
            //系统顶层窗口,显示在其他一切内容之上,此窗口不能获得输入焦点,否则影响锁屏
            public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;
            //电话优先,当锁屏时显示,此窗口不能获得输入焦点,否则影响锁屏
            public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;
            //系统对话框窗口
            public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;
            //锁屏时显示的对话框
            public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;
            //系统内部错误提示,显示在任何窗口之上
            public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;
            //内部输入法窗口,显示于普通UI之上,应用程序可重新布局以免被此窗口覆盖
            public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;
            //内部输入法对话框,显示于当前输入法窗口之上
            public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
            //墙纸窗口
            public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;
            //状态栏的滑动面板
            public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;
            //安全系统覆盖窗口,这些窗户必须不带输入焦点,否则会干扰键盘
            public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
            //最后一个系统窗口
            public static final int LAST_SYSTEM_WINDOW      = 2999;
    
            ........
    
            //窗口特征标记
            public int flags;
            //当该window对用户可见的时候,允许锁屏
            public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001;
            //窗口后面的所有内容都变暗
            public static final int FLAG_DIM_BEHIND        = 0x00000002;
            //Flag:窗口后面的所有内容都变模糊
            public static final int FLAG_BLUR_BEHIND        = 0x00000004;
            //窗口不能获得焦点
            public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;
            //窗口不接受触摸屏事件
            public static final int FLAG_NOT_TOUCHABLE      = 0x00000010;
            //即使在该window在可获得焦点情况下,允许该窗口之外的点击事件传递到当前窗口后面的的窗口去
            public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020;
            //当手机处于睡眠状态时,如果屏幕被按下,那么该window将第一个收到触摸事件
            public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
            //当该window对用户可见时,屏幕出于常亮状态
            public static final int FLAG_KEEP_SCREEN_ON     = 0x00000080;
            //:让window占满整个手机屏幕,不留任何边界
            public static final int FLAG_LAYOUT_IN_SCREEN   = 0x00000100;
            //允许窗口超出整个手机屏幕
            public static final int FLAG_LAYOUT_NO_LIMITS   = 0x00000200;
            //window全屏显示
            public static final int FLAG_FULLSCREEN      = 0x00000400;
            //恢复window非全屏显示
            public static final int FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800;
            //开启窗口抖动
            public static final int FLAG_DITHER             = 0x00001000;
            //安全内容窗口,该窗口显示时不允许截屏
            public static final int FLAG_SECURE             = 0x00002000;
    
    
            //锁屏时显示该窗口
            public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
            //系统的墙纸显示在该窗口之后
            public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
            //当window被显示的时候,系统将把它当做一个用户活动事件,以点亮手机屏幕
            public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
            //该窗口显示,消失键盘
            public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
            //当该window在可以接受触摸屏情况下,让因在该window之外,而发送到后面的window的触摸屏可以支持split touch
            public static final int FLAG_SPLIT_TOUCH = 0x00800000;
            //对该window进行硬件加速,该flag必须在Activity或Dialog的Content View之前进行设置
            public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;
            //让window占满整个手机屏幕,不留任何边界
            public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
            //透明状态栏
            public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;
            //透明导航栏
            public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;
    
    
            ..........
            //软输入法模式
            public int softInputMode;
    
            //用于描述软键盘显示规则的bite的mask
            public static final int SOFT_INPUT_MASK_STATE = 0x0f;
            //没有软键盘显示的约定规则
            public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
            //可见性状态softInputMode,请不要改变软输入区域的状态
            public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
            //用户导航(navigate)到你的窗口时隐藏软键盘
            public static final int SOFT_INPUT_STATE_HIDDEN = 2;
            //总是隐藏软键盘
            public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
            //用户导航(navigate)到你的窗口时显示软键盘
            public static final int SOFT_INPUT_STATE_VISIBLE = 4;
            //总是显示软键盘
            public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
            //显示软键盘时用于表示window调整方式的bite的mask
            public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
            //不指定显示软件盘时,window的调整方式
            public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
            //当显示软键盘时,调整window内的控件大小以便显示软键盘
            public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
            //当显示软键盘时,调整window的空白区域来显示软键盘,即使调整空白区域,软键盘还是有可能遮挡一些有内容区域,这时用户就只有退出软键盘才能看到这些被遮挡区域并进行
            public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
            //当显示软键盘时,不调整window的布局
            public static final int SOFT_INPUT_ADJUST_NOTHING = 0x30;
            //用户导航(navigate)到了你的window
            public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
    
    
            //窗口的对齐方式
            public int gravity;
    
            //期望的位图格式,默认为不透明,参考android.graphics.PixelFormat
            public int format;
            //窗口所使用的动画设置,它必须是一个系统资源而不是应用程序资源,因为窗口管理器不能访问应用程序
            public int windowAnimations;
            //整个窗口的半透明值,1.0表示不透明,0.0表示全透明
            public float alpha = 1.0f;
            //当FLAG_DIM_BEHIND设置后生效,该变量指示后面的窗口变暗的程度,1.0表示完全不透明,0.0表示没有变暗
            public float dimAmount = 1.0f;
    
            public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
            public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
            public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
            public float screenBrightness = BRIGHTNESS_OVERRIDE_NONE;
            //用来覆盖用户设置的屏幕亮度,表示应用用户设置的屏幕亮度,从0到1调整亮度从暗到最亮发生变化
            public float buttonBrightness = BRIGHTNESS_OVERRIDE_NONE;
    
            public static final int ROTATION_ANIMATION_ROTATE = 0;
            public static final int ROTATION_ANIMATION_CROSSFADE = 1;
            public static final int ROTATION_ANIMATION_JUMPCUT = 2;
            //屏幕旋转动画
            public int rotationAnimation = ROTATION_ANIMATION_ROTATE;
    
            //窗口的标示符
            public IBinder token = null;
            //此窗口所在应用的包名
            public String packageName = null;
            //窗口屏幕方向
            public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
    
            //控制status bar是否可见,两种赋值  View#STATUS_BAR_VISIBLE;View#STATUS_BAR_HIDDEN
            public int systemUiVisibility;
    
            ......
    
        }
    }
    
    

    提取几个重要的参数

    • width:描述窗口的宽度,该变量是父类ViewGroup.LayoutParams的成员变量。
    • height:描述窗口的高度,该变量同样是父类ViewGroup.LayoutParams的成员变量。
    • x:描述窗口的起点X轴的坐标。
    • y:描述窗口起点Y轴的坐标。
    • type:窗口的类型,分为三个大类型:应用窗口,子窗口,系统窗口。
    • flag:窗口特征标记,比如是否全屏,是否隐藏标题栏等。
    • gravity:窗口的对齐方式,居中还是置顶或者置底等等。

    Window是一个是一个抽象的概念,千万不要认为我们所看到的就是Window,我们平时所看到的是视图,每一个Window都对应着一个View,View和Window通过ViewRootImpl来建立联系。有了View,Window的存在意义在哪里呢,因为View不能单独存在,它必须依附着Window,所以有视图的地方就有Window,比如Activity,一个Dialog,一个PopWindow,一个菜单,一个Toast等等。

    3、Window的创建过程与显示过程

    通过上面我们知道视图和Window的关系,那么有一个问题,是先有视图,还是先有Window。这个答案只有在源码中找了。应用程序的入口类是ActivityThread,在ActivityThread中有performLaunchActivity来启动Activity,这个performLaunchActivity方法内部会创建一个Activity。

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            ...
            Activity activity = null;
            try {
              //通过反射机制创建一个Activity 
                java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
                activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent);
                StrictMode.incrementExpectedActivityCount(activity.getClass());
                r.intent.setExtrasClassLoader(cl);
                r.intent.prepareToEnterProcess();
                if (r.state != null) {
                    r.state.setClassLoader(cl);
                }
            } catch (Exception e) {
              ...
            }
    
            try {
                Application app = r.packageInfo.makeApplication(false, mInstrumentation);
                if (activity != null) {
                    Context appContext = createBaseContextForActivity(r, activity);
                    CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                    Configuration config = new Configuration(mCompatConfiguration);
                    //这个里面创建了Window对象
                    activity.attach(appContext, this, getInstrumentation(), r.token,
                            r.ident, app, r.intent, r.activityInfo, title, r.parent,
                            r.embeddedID, r.lastNonConfigurationInstances, config,
                            r.referrer, r.voiceInteractor);
    
                   }
    
                  activity.mCalled = false;
                   if (r.isPersistable()) {
                        //调用Activity的onCreate方法
                       mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                   } else {
                       mInstrumentation.callActivityOnCreate(activity, r.state);
                   }
    
                mActivities.put(r.token, r);
                ...
            }  catch (Exception e) {
             ...
            }
            return activity;
        }
    

    如果activity不为null,就会调用attach,在attach方法中通过PolicyManager创建了Window对象,并且给Window设置了回调接口。

    mWindow = PolicyManager.makeNewWindow(this);
    mWindow.setCallback(this);/设置回调函数,使得Activity可以处理一些事件  
    

    PolicyManager的实现类是Policy

    public Window makeNewWindow(Context context) { 
          return new PhoneWindow(context);
     }
    

    这样Window就创建出来了,所以先有Window,后有视图,视图依赖Window存在,再说一说视图(Activity)为Window设置的回调接口。

        /**
         * API from a Window back to its caller.  This allows the client to
         * intercept key dispatching, panels and menus, etc.
         */
        public interface Callback {
           
            public boolean dispatchKeyEvent(KeyEvent event);
            
            public boolean dispatchKeyShortcutEvent(KeyEvent event);
    
            public boolean dispatchTouchEvent(MotionEvent event);
    
            public boolean dispatchTrackballEvent(MotionEvent event);
    
            public boolean dispatchGenericMotionEvent(MotionEvent event);
    
            public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event);
            
            public View onCreatePanelView(int featureId);
    
            public boolean onCreatePanelMenu(int featureId, Menu menu);
    
            public boolean onPreparePanel(int featureId, View view, Menu menu);
    
            public boolean onMenuOpened(int featureId, Menu menu);
    
            public boolean onMenuItemSelected(int featureId, MenuItem item);
           
            public void onWindowAttributesChanged(WindowManager.LayoutParams attrs);
    
            public void onContentChanged();
    
            public void onWindowFocusChanged(boolean hasFocus);
    
            public void onAttachedToWindow();
    
            public void onDetachedFromWindow();
    
            public void onPanelClosed(int featureId, Menu menu);
    
            public boolean onSearchRequested();
    
            public ActionMode onWindowStartingActionMode(ActionMode.Callback callback);
         
            public void onActionModeStarted(ActionMode mode);
            
            public void onActionModeFinished(ActionMode mode);
        }
    

    Activity实现了这个回调接口,当Window的状态发生变化的时候,就会回调Activity中实现的这些接口,有些回调接口我们还是熟悉的,dispatchTouchEvent,onAttachedToWindow,onDetachedFromWindow等。

    下面分析view是如何附属到window上的,通过上面可以看到,在attach之后就要执行callActivityOnCreate,在onCreate中我们会调用setContentView方法。

      public void setContentView(int layoutResID) {  
            getWindow().setContentView(layoutResID);  
            initWindowDecorActionBar();  
        }  
    
    

    getWindow获取了Window对象,Window的具体实现类是PhoneWindow,所以要看PhoneWindow的setContentView方法。

     public void setContentView(int layoutResID) {
            // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
            // decor, when theme attributes and the like are crystalized. Do not check the feature
            // before this happens.
            if (mContentParent == null) {
              //第一步,构建DecroView
                installDecor();
            } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                mContentParent.removeAllViews();
            }
    
            if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                        getContext());
                transitionTo(newScene);
            } else {
              //第二步,将View添加到mContentParent中
                mLayoutInflater.inflate(layoutResID, mContentParent);
            }
            final Callback cb = getCallback();
            if (cb != null && !isDestroyed()) {
              //第三步,回调Activity的onContentChanged方法,通知视图发生了改变
                cb.onContentChanged();
            }
        }
    

    这里涉及到一个mContentParent变量,他是一个DecorView的一部分,DecorView是PhoneWindow的一个内部类,我先介绍一下关于DecorView的知识。

    DecorView

    DecorView是Activity的顶级VIew,DecorView继承自FrameLayout,在DecorView中有上下两个部分,上面是标题栏,下面是内容栏,我们通过PhoneWindow的setContentView所设置的布局文件是加到内容栏(mContentParent)里面的,View层的事件都是先经过DecorView在传递给我们的View的。

    OK在回到setContentView的源码分析,我们可以得到Activity的Window创建需要三步。

    - 1、 如果没有DecorView,在installDecor中创建DecorView。

    - 2、将View添加到decorview中的mContentParent中。

    - 3、回调Activity的onContentChanged接口。

    先看看第一步,installDecor的源码

    ...
      if (mDecor == null) {
           mDecor = generateDecor();
            ...
      }
     ...
    

    installDecor中调用了generateDecor,继续看

     protected DecorView generateDecor() {
            return new DecorView(getContext(), -1);
        }
    

    直接给new一个DecorView,有了DecorView之后,就可以加载具体的布局文件到DecorView中了,具体的布局文件和系统和主题有关系。

      if (mContentParent == null) {
                mContentParent = generateLayout(mDecor);
      }
    
      View in = mLayoutInflater.inflate(layoutResource, null);
      decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
       mContentRoot = (ViewGroup) in;
    
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
       if (contentParent == null) {
           throw new RuntimeException("Window couldn't find content container view");
       }
    
    

    在看第二步,将View添加到decorview中的mContentParent中。

      mLayoutInflater.inflate(layoutResID, mContentParent);
    

    直接将Activity视图加到DecorView的mContentParent中,最后一步,回调Activity的onContentChanged接口。在Activity中寻找onContentChanged方法,它是个空实现,我们可以在子Activity中处理。

    public void onContentChanged() {}
    

    到此DecorView被创建完毕,我们一开始从Thread中的handleLaunchActivity方法开始分析,首先加载Activity的字节码文件,利用反射的方式创建一个Activity对象,调用Activity对象的attach方法,在attach方法中,创建系统需要的Window并为设置回调,这个回调定义在Window之中,由Activity实现,当Window的状态发生变化的时候,就会回调Activity实现的这些回调方法。调用attach方法之后,Window被创建完成,这时候需要关联我们的视图,在handleLaunchActivity中的attach执行之后就要执行handleLaunchActivity中的callActivityOnCreate,在onCreate中我们会调用setContentView方法。通过setContentView,创建了Activity的顶级View---DecorView,DecorView的内容栏(mContentParent)用来显示我们的布局。这个是我们上面分析得到了一个大致流程,走到这里,这只是添加的过程,还要有一个显示的过程,显示的过程就要调用handleLaunchActivity中的handleResumeActivity方法了。最后会调用makeVisible方法。

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

    这里面首先拿到WindowManager对象,用tWindowManager 的父接口ViewManager接收,ViewManager可以
    最后调用 mDecor.setVisibility(View.VISIBLE)设置mDecor可见。到此,我们终于明白一个Activity是怎么显示在我们的面前了。
    参考链接:
    http://blog.csdn.net/feiduclear_up/article/details/49201357

    相关文章

      网友评论

      • umbrella1:一个Activity对应一个PhoneWindow,dialog也有一个PhoneWindow,搞不明白,这个dialog的window和activity有什么关联?
        LooperJing:@umbrella1 Activity窗口是个PhoneWindow,Dialog构造函数中也是new的PhoneWindow,两者PhoneWindow不是同一个对象
      • 红橙Darren:写得很不错啊,之前也看过,但是没关注过WindowManager自己还是看得比较浅
        红橙Darren: @LooperJing 没多少😂😂😂
        LooperJing:@红橙Darren 发现你也写了好多的博客啊
      • 锅炉工:应该是先有Window再有View的吧,ActivityThread先创建的Window,之后才callActivityOnCreate() 的,而View是在PhoneWindow的setContentView里inflate出来的。:innocent:
        LooperJing:文中加粗的部分说到:“到此DecorView被创建完毕,我们一开始从Thread中的handleLaunchActivity方法开始分析,首先加载Activity的字节码文件,利用反射的方式创建一个Activity对象,调用Activity对象的attach方法,在attach方法中,创建系统需要的Window并为设置回调,这个回调定义在Window之中,由Activity实现,当Window的状态发生变化的时候,就会回调Activity实现的这些回调方法。调用attach方法之后,Window被创建完成,这时候需要关联我们的视图,在handleLaunchActivity中的attach执行之后就要执行handleLaunchActivity中的callActivityOnCreate,在onCreate中我们会调用setContentView方法。通过setContentView,创建了Activity的顶级View---DecorView,DecorView的内容栏(mContentParent)用来显示我们的布局”
      • 掏钱:写的不错,但是有一点,感觉国内很多人都有所误解,那就是并不是所有view的显示都需要我们理解的window这个对象,PopuoWindow根本就没有创建window对象,普通的显示一个view,也只是通过windowmanager去addview就行了。甚至可以大胆的猜测,view的显示根本就不需要window这个对象,而activity和dialog里有这个window对象,只是方便管理而已,真正的window对象应该是最底层实现的。
        LooperJing:@掏钱 确实没有,PopuoWindow只是Activity上悬浮的一个容器而已
      • 688266c0a195:加油!
        LooperJing:@低声呢喃感觉没什么时间写

      本文标题:Android源码解析Window系列第(一)篇---Windo

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