android 窗口管理机制详解

 Android系统启动篇

1,《android系统启动流程简介》

2,《android init进程启动流程》

3,《android zygote进程启动流程》

4,《Android SystemServer进程启动流程》

5,《android launcher启动流程》

6,《Android Activity启动过程详解》

Android系统开发准备篇

1,《Android 源码下载和编译》

2,《android 11源码编译和pixel3 刷机》

3,《Android Framework代码IDE加载和调试》

Android系统开发实践篇

1,《android设置默认输入法》

2,《android framework预制APK应用》

3,《Android系统层面限制应用开机自启动详解》

4,《android单独编译framework模块并push》

5,《Android Framework开发系统问题分析》

Android系统开发核心知识储备篇

1,《Android编译系统-envsetup和lunch代码篇》

2,《Android编译系统-概念篇》

3,《android日志系统详解》

4,《Android系统Handler详解》

5,《Android系统Binder详解》

6,《Android中Activity、View和Window关系详解》

7,《android view绘制流程详解》

8,《Android读取系统属性详解》

9,《android 窗口管理机制详解》

10,《初识Android系统》

11,《android中AMS进程通知Zygote进程fork新进程的通信方式》

Android核心功能详解篇

1,《android应用市场点击下载APK安装详解》

2,《Android 手势导航(从下往上滑动进入多任务页面)》

3,《android手势分析(应用界面左往右边滑动退出应用)》

4,《android应用安装流程详解》

5,《android11安装应用触发桌面图标刷新流程》

6,《Android系统多任务Recents详解》

7,《android系统导航栏视图分析》

———————————————————————————————————————————

目录

一,基础介绍

二,Window

三,WindowManager

四、WindowManagerService

五,总结

一,基础介绍

        Android的窗口管理主要由Window, WindowManager, WindowManagerService三者实现。Window表示的是一种抽象的功能集合,具体实现为PhoneWindow。WindowManager是外界访问Window的入口,对Window的访问必须通过WindowManager,而WindowManger和WindowManagerService的交互是一个跨进程通信过程。Android中所有的视图都是通过Window来呈现的,不管是Activity、Dialog、Toast,他们的视图都是附加在Window上的。关系如下图,

二,Window

        FrameWork定义了三种窗口类型,三种类型定义在WindowManager。

1.应用窗口,对应于一个Activity。加载Activity由AmS完成,创建一个应用窗口只能在Activity内部完成。

2.子窗口,必须依附于任何类型的父窗口。

3.系统窗口,不需要对应任何Activity,应用程序不能创建系统窗口。

        WindowManager为这个三类进行了细化,把每一种类型都有int常量标识,WmS进行窗口叠加的时候会按照该int常量的大小分配不同层,int值越大层位置越靠上面,这里的int值称之为层级。

        每个 Window 都有对应的 z-ordered,层级大的会覆盖在层级小的 Window 上面,这和 HTML 中的 z-index 概念是完全一致的。在三种 Window 中,应用 Window 层级范围是 1~99,子 Window 层级范围是 1000~1999,系统 Window 层级范围是 2000~2999,这些层级范围对应着 WindowManager.LayoutParams 的 type 参数,如果想要 Window 位于所有 Window 的最顶层,那么采用较大的层级即可,很显然系统 Window 的层级是最大的。各个窗口类型和TYPE对应关系如下,

这里写图片描述

这里写图片描述

这里写图片描述         

        Window是一个抽象概念,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系。如下图所示:

三,WindowManager

        WindowManager是整个窗口管理机制里面的枢纽,也是这边重点要讲的。WindowManager实现了ViewManager,这个接口定义了我们对于Window的基本操作:


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 对外提供的主要功能,即添加 View、更新 View 和删除 View。看一个通过 WindowManager 添加 Window 的例子:


public class MainActivity extends AppCompatActivity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        Button floatingButton = new Button(MainActivity.this);

        floatingButton.setText("button");

        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(

                WindowManager.LayoutParams.WRAP_CONTENT,

                WindowManager.LayoutParams.WRAP_CONTENT,

                0, 0,

                PixelFormat.TRANSPARENT

        );

        // flag 设置 Window 属性

        layoutParams.flags= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;

        // type 设置 Window 类别(层级)

        layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

        layoutParams.gravity = Gravity.CENTER;

        WindowManager windowManager = getWindowManager();

        windowManager.addView(floatingButton, layoutParams);

    }

}

效果如下,

        在Activity启动过程中ActivityThread会调用performLaunchActivity()这个函数,这个函数里面会经过层层深入会调用Activity的OnCreate()方法,而在performLaunchActivity()中调用OnCreate()方法前会调用Activity的attach()方法,


// ActivityThread.class

final void attach(Context context, ActivityThread aThread,

            Instrumentation instr, IBinder token, int ident,

            Application application, Intent intent, ActivityInfo info,

            CharSequence title, Activity parent, String id,

            NonConfigurationInstances lastNonConfigurationInstances,

            Configuration config, String referrer, IVoiceInteractor voiceInteractor,

            Window window, ActivityConfigCallback activityConfigCallback) {

        ...

        // 创建PhoneWindow并设置其回调接口

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

        mWindow.setWindowControllerCallback(this);

        mWindow.setCallback(this);

        mWindow.setOnWindowDismissedCallback(this);

        mWindow.getLayoutInflater().setPrivateFactory(this);

        ...

        // 将该Window和WindowManager绑定

        mWindow.setWindowManager(

                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),

                mToken, mComponent.flattenToString(),

                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);

    ...

        // 设置管理Activity的Window的WindowManager

        mWindowManager = mWindow.getWindowManager();

    ...

    }

在attach()这个方法中创建了Activity的Window,同时为该Window绑定WindowManager,将这个WindowManager传给Activity的成员变量mWindowManager。同时我们可以看到Window 的具体实现类是PhoneWindow。

进去setWindowManager()方法中看一下:


public void setWindowManager(WindowManager wm, IBinder appToken, String appName,

            boolean hardwareAccelerated) {

    ...

        if (wm == null) {

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

        }

        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);

    }

        这个方法主要做了创建出Activity的Window对象,并且获取了管理该Window的WindowManager。而此时其实并没有将Activity对应的View附属到这个Window中。而将这个View附属到Window的代码其实就是我们在OnCreate() 中常调用的setContentView(int layoutResID):


// Activity.class

public void setContentView(int layoutResID){

  getWindow().setContentView(layoutResID);

   ...

}

        该方法调用最终调用的是getWindow()的setContentView(layoutResID),而getWindow()获取的就是在attach()中创建的PhoneWindow,我们再进去看一下:


// PhoneWindow.class

 @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }

        调用setContentView将window与View绑定在一起。可以看到,首先判断mContentParent是否为null,是则调用installDecor(),否则移除其内部所有的子Views,然后通过LayoutInflater.inflate将我们传入的layout放置到mContentParent中。

        在Activity调用onResume方法之后,会调用makeVisible()方法,将window加入到windowManager中,那么windowManager就可以对window进行管理了。


void makeVisible() {

        if (!mWindowAdded) {

            ViewManager wm = getWindowManager();

            wm.addView(mDecor, getWindow().getAttributes());

            mWindowAdded = true;

        }

        mDecor.setVisibility(View.VISIBLE);

    }

        window是抽象的,必须通过windowManager对其进行访问,windowManager是继承自viewmanager的,它提供了对视图的增,删,改操作。而视图是与window绑定在一起的,所以对View的操作其实也是对window的操作。
        上面代码中可以看出,windowManager的具体实现类其实是WindowManagerImpl,


@Override

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

        ...

            mGlobal.addView(view, params, mDisplay, mParentWindow);

        }

        @Override

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

        ...

            mGlobal.updateViewLayout(view, params);

        }

        @Override

        public void removeView(View view){

        ...

            mGlobal.removeView(view, false);

        }


它把对视图的操作都交给了成员mGlobal去实现,mGlobal是一个WindowManagerGlobal类,再看一下它的源码,mGlobal中提供了对视图进行增、删、改的操作函数,同时还用了几个集合来保存和window相关的信息,具体如下。

public final class WindowManagerGlobal{
	// 存储所有window对应的View
    private final ArrayList<View> mViews = new ArrayList<View>();
	// 存储所有window对应的ViewRootImpl
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    // 存储所有的window对应的布局参数 
    private final ArrayList<WindowManager.LayoutParams> mParams =new ArrayList<WindowManager.LayoutParams>();
     //  存储已经调用removeView方法但是操作删除还未完成的对象
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

	public void addView(...){
		...
	}
	public void updateViewLayout(...){
		...
	}
	public void removeView(...){
		...
	}
	...
}

        WindowManager到WindowManagerService的调用路径为

四、WindowManagerService

        上文已经通过WindowManagerService 的代理调用了其addWindow()方法,该方法非常复杂。主要的操作就是将传来的Window 根据它的参数,尤其是其type,保存起来。方便SurfaceFlinger渲染。

     在文件IWindowManager.aidl中,我们可以看到WindowManagerService可以提供哪些功能

......
    void getBaseDisplaySize(int displayId, out Point size);
    void setForcedDisplaySize(int displayId, int width, int height);
    void clearForcedDisplaySize(int displayId);
    @UnsupportedAppUsage
    int getInitialDisplayDensity(int displayId);
    int getBaseDisplayDensity(int displayId);
    void setForcedDisplayDensityForUser(int displayId, int density, int userId);
    void clearForcedDisplayDensityForUser(int displayId, int userId);
    void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable

    void setOverscan(int displayId, int left, int top, int right, int bottom);

    // These can only be called when holding the MANAGE_APP_TOKENS permission.
    void setEventDispatching(boolean enabled);
    void addWindowToken(IBinder token, int type, int displayId);
    void removeWindowToken(IBinder token, int displayId);
    void setFocusedApp(IBinder token, boolean moveFocusNow);
    void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
    ......

        从接口定义中可以看到,WMS的功能庞杂繁多,比如获取显示器的信息,截取屏幕,锁定屏幕等各种功能。

五,总结

        android窗口管理流程大致如下:

1,创建Window,将View和ViewRootImpl同Window绑定。

2,WindowManager的addView()、updateViewLayout() 和 removeView()方法操作Window。

3, 将WindowManager这些操作方法转移给WindowManagerGobal来调用。

4,调用与Window绑定的ViewRootImpl的setView()方法。

5,setView()方法里面会通过mWindowSession这个Binder对象将Window传给WindowManagerService。

6,WindowManagerService来管理各个Window的大小和显示位置,来让SurfaceFlinger渲染。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

佳哥的技术分享

创作不易,谢谢鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值