WMS工作原理分析

本文详细介绍了Window Manager Service (WMS) 的工作机制,包括窗口、Window和View的区别,WMS接口结构及其交互过程,以及窗口的创建时机和过程。特别关注了通过WindowManager添加和移除窗口的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Wms管理着所有的窗口,包括创建、删除和修改,以及将某个窗口设置为焦点窗口。

一、窗口、Window和View的区别

窗口由两部分构成,一部分是描述该窗口的类WindowState,另一部分是该窗口在屏幕上对应的界面Surface。

window是一个类,其实现类是PhoneWindow类,Activity类实现Window.Callback接口,从而成了具有通用操作方式的窗口。

View也是一个视图,是一个独立的交互元素。

二、Wms接口结构

交互过程如下:

  1. 应用程序在Activity中添加、删除窗口。具体实现就是通过调用WindowManager类的addView()和removeView()函数完成,转而调用ViewRoot类的相关方法,然后通过IPC调用到Wms中的相关方法完成添加、删除过程。

  2. AmS通知ActivityThread销毁某个Actviity时,ActivityThread会直接调用WindowManager中的removeView()方法删除窗口。

  3. AmS中直接调用WmS,告诉Wms一些信息,比如某个新的Activity要启动了,从而Wms保存一个该Activity记录的引用。

  4. 在Wms内部,全权接管输入消息的处理和屏幕的绘制。输入消息由InputManager类完成,屏幕绘制由SurfaceFlinger模块完成,SurfaceFlings是Linux的一个驱动,内部使用芯片的图形加速引擎完成界面的绘制。

三、窗口的创建时机和过程

时机:第一种是开发者主动调用WindowManager类的addView()方法;第二种是当用户启动新的Activity或者显示一个对话框的时候,由类内部间接调用addView()函数。

以第二种窗口创建为例,activity启动执行performLaunchActivity函数,创建activity对象、ContextImpl对象和Application对象,然后调用activity.attach()函数,创建Window实现类PhoneWindow对象,回调Activity的onCreate()函数,setContentView(view)初始化DecorView。接着调用handleResumeActivity函数,调用windowManage.addView(decor)。windowManager的实现类是windowManagerImpl类,看下它的addView()方法。

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

调用到WindowManagerGlobal.addView()函数。

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
           ...
    ViewRootImpl root;
    View panelParentView = null;
         ...

        root = new ViewRootImpl(view.getContext(), display);

        view.setLayoutParams(wparams);

        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
    }

    // do this last because it fires off messages to start doing things
    try {
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
        // BadTokenException or InvalidDisplayException, clean up.
        synchronized (mLock) {
            final int index = findViewLocked(view, false);
            if (index >= 0) {
                removeViewLocked(index, true);
            }
        }
        throw e;
    }
}

初始化调用到ViewRootImpl对象,在构造函数中获取WindowSession对象,windowSession会通过IPC创建Session对象。它是一个SurfaceSession对象的包装类,直接和SurfaceFlinger对象直接打交道,SurfaceFlinger对象是底层界面绘制类。接着看ViewRootImpl.setView()方法。setView函数主要做两件事情,一是requestLayout(),请求绘制界面scheduleTraversals()。二是创建InputChannel消息传输渠道对象,他是对Unxi Socket对的封装,在系统server和程序中各有一个,作用是对消息的读取。三是调用session.addToDisplay(),继而调用wms.addWindow()函数。

addWindow方法的执行流程分为三个小过程,第一个是进行前置处理,即首先判断参数的合法性,二是具体添加和窗口相关的数据,第三是后置处理,即添加窗口会引起相关状态的变化。

  1. 判断mDisplay是否为空,该变量为全局变量,代表当前屏幕的Display属性,该代码当系统启动后仅被执行一次。

  2. 判断目标窗口是否已经存在mWindowMap列表中,此时目标是IWindow类型,其对应是ViewRoot类中的W对象。如果已经存在,抛出异常提示重复添加。

  3. 如果目标窗口参数attr.type=SUB_WINDOW,即子窗口类型,那么目标窗口所隶属的父窗口必须存在,否则添加无效。

当前置检查完成后,没什么错误,就开始真正窗口的添加。

  1. 新建一个windowState对象,窗口都是由WindowState类表示,每个窗口对应一个WindowState对象。

  2. 调用mPolicy.adjustWindowParamsLw()对窗口参数进行调整,对TOAST窗口限制其获得输入焦点的功能。

  3. 创建一对pipe,一个赋值给输出参数outchannel变量中,另一个赋值给InputDispatcher中,管道将用于输入消息的传递。

  4. 调用win.attach()方法,内部初始化和创建真正的Surface相关的变量,主要是SurfaceSession变量,该类直接和SurfaceFlinger交互的类,用于向SurfaceFlinger中添加、删除、变换窗口。SurfaceSession构造函数中调用了nativeCreate(),属于native层方法,主要是创建爱你一块共享内存,通过writeParcel返回给ViewRootImlp.mSurface

  5. 将新建的windowState对象那个添加到mWindowMap列表中。

后置处理:

### Android 平台上的 WMS 实现与集成分析 在讨论 Android 平台上 WMS(Web Map Service)的实现与集成之前,需了解 WMS 是一种基于 OGC(开放地理空间联盟)标准的服务接口,用于提供地图图像数据。这些服务通常通过 HTTP 请求获取栅格地图图像并将其显示于客户端应用中。 #### 1. WMS 集成的基础原理 WMS 提供的地图图像是由服务器端动态生成的,支持多种投影方式以及不同比例尺下的地图渲染。为了在 Android 应用程序中集成 WMS 功能,开发者可以利用现有的开源库来简化开发流程[^3]。例如,Leaflet 和 OpenLayers 虽然主要用于 Web 地图展示,但它们的理念同样适用于移动设备环境中的地图加载逻辑。 对于 Android 原生应用程序而言,推荐使用 **OSMDroid** 或者 **Mapbox SDK** 这样的工具包作为基础框架[^1]。这两种解决方案都允许自定义瓦片源,并能够轻松接入来自第三方 WMS 服务提供商的数据流。 #### 2. 技术选型建议 当考虑如何实现在 Android 设备上访问远程 GIS 数据时,可以选择以下几种方法之一: - 使用内置 WebView 控件加载 HTML5 页面,在其中嵌入 JavaScript API 来调用 WMS 层; - 利用专门针对移动端优化过的 Java/Kotlin 类库直接处理网络请求并与本地 UI 组件交互; 下面给出一段简单的代码示例演示第二种方案的部分功能实现过程: ```java import org.osmdroid.tileprovider.tilesource.XYTileSource; //... public class CustomWMSTileSource extends XYTileSource { public CustomWMSTileSource(String name, int minZoomLevel, int maxZoomLevel, ITileSource tileSource) throws IOException { super(name, null, minZoomLevel, maxZoomLevel, TILE_SIZE_PIXELS, ".png", new String[]{}); // 构建完整的URL模板字符串... } } ``` 此片段展示了创建一个新的 Tile Source 对象的过程,它将被用来配置 OSMDroid 显示特定范围内的地图切片。实际项目里还需要补充更多细节才能完成整个系统的搭建工作。 另外值得注意的是,如果目标环境中缺乏必要的依赖项,则可能需要借助虚拟机技术预先准备好运行条件。比如可以通过设置 `ubuntugis-docker` 容器镜像快速部署适合开展此类任务的工作区[^2]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值