Android平台浏览器当前多窗口方案为多个浏览器子窗口公用一个图形buffer,窗口的z序和显示控制由浏览器进程维护,图形侧只能看到一个窗口。该方案能基本实现浏览器多窗口的大部分需求。但无法实现linux机顶盒中存在的部分窗口交叉的业务场景,即在浏览器多个窗口间交叉存在其他应用窗口(图1)。

4设计思路

4.1Android和其他系统(Qt/Windows)窗口概念的差异

1.进程、窗口、生命周期

在windows和linux系统中,在程序启动之后,排除意外情况,程序的退出基本由程序自己控制,期间没有什么状态切换。(不考虑资源阻塞和内核调度,这些对应用程序基本是透明的)

Android的一个应用在底层也是linux的一个进程,但在上层弱化了进程的概念,抽象出了Activity这样一种交互。代码直接控制的是Activity,用户的交互也是Activity。

Activity是从用户交互的角度抽象出来的一个对象,在概念和使用上和进程相隔离。进程类似一个收养的功能,一个进程可以有多个Activity,不仅可以收养自己当前应用的Activity,也可以收养其他安装包指定给该进程的Activity,Activity销毁了,进程并不销毁(除非系统需要或代码强制杀死进程)。

可以简单理解为,在win/linux中,一个进程有多个窗口,用户和每个window进行交互,在Android中,用户“跳过”进程,直接和窗口Activity交互,

Android对Activity提出了生命周期的概念,下面是摘抄自google sdk的描述

2.Activity生命周期的主要影响

1.系统侧:内存低时,会杀掉非active的Activity(即:不在最上层的Activity)

2.应用侧:当应用程序在非active状态时,可以释放部分资源和停止部分操作来降低CPU和内存的使用。(如浏览器非active时执行gc,停止网络,停止webkit的内核时钟…)

3.父子窗口间的通讯

在Win/Qt中,一个进程可以有多个窗口,在进程中,通过窗口句柄,可以完成对窗口内容的绘制。

Android中,Activity之间并不存在窗口句柄的概念,Activity之间不是父子的关系,是兄弟的关系。两个Activity之间只能在开启Activity时通过入参传递内容,在Activity启动之后,通过IPC(broadcast、content provider,binder…)完成数据交互,类似两个进程间通讯,在同一个进程的多个Activity对象也可以通过同一个Application对象进行数据交互。

4.2其他系统Qt/Windows多窗口及z序的实现

Qt中多窗口的实现:

BrowserMainWindow *browser = new BrowserMainWindow();

//向图形申请新窗口,返回窗口句柄

……

browser->show();//通过句柄直接操作该窗口

原始Qt中的z序

在Qt中所有窗口由窗口管理器进行管理,来实现Z序及按键派发。但不支持函数接口设置窗口的z序。窗口的z序为窗口启动的顺序。

窗口焦点属性(focusable/unfocusable)已提供接口,由应用程序设置widget属性来控制窗口是否可接受按键消息。

z序的主要修改

1.提供接口设置窗口的z序,实现混屏操作,将窗口显示出来

2.选择正确的焦点窗口,将用户事件(鼠标、键盘)派发到该窗口

4.3Android 多activity和已有 z序

Android开启activity使用系统startActivity函数,函数声明如下

public void startActivity (Intent intent)

使用方法:

startActivity (new Intent(BrowserActivity.ACTION_RESTART, null, getActivity(), BrowserActivity.class));

Android中已有的z序

Android中activity的Z序并不直接由Activity和WindowManagerService(后文简写为WMS)进行交互,而是由ActivityManagerService (后文简写为AMS) 来触发管理。当用户在某个Activity交互过程中请求另一个Activity时,当前Activity会向AMS发起请求,由AMS对请求进行解析、处理,之后启动新的Activity,在新Activity启动流程中,会attach到WindowManagerService中,完成窗口的显示。在新旧窗口的更换过程中,AMS会负责改变2个Activity的状态。

在Android中的Activity的交互请求都是直接和AMS进行交互,窗口的操作是附属在AMS管理的流程中。

4.4Android浏览器图形侧多窗口方案

方案一

Android使用多activity实现浏览器的多窗口主要有以下困难:

1.得不到窗口的句柄,不易于操作数据。(浏览器)

2.在窗口切换时存在生命周期的切换 (浏览器)

已上问题导致了,浏览器通过多Activity实现多窗口在数据的管理和状态的控制上均是比较困难的。

方案二

在Android中,提供了一种创建临时窗口的方法,即跳过AMS,直接和WMS交互,生成新窗口,在Android中的Dialog提示框就是这样实现的。因为绕过了AMS,所以在创建新窗口时,不存在生命周期切换的问题,另外,也可以直接控制绘图的区域。

调用方法为:

wm=(WindowManager)getApplicationContext().getSystemService(“window”);

//得到系统WMS服务的binder对象

//wmParams 设置窗口属性

….

//请求WMS生成一个窗口,并将myView加到窗口内容中

wm.addView(myView, wmParams);

4.5浏览器多窗口实现效果

测试环境为Widget测试页面,图中左侧的菜单栏和右侧的时钟显示分别在2个窗口中,左侧菜单栏为父窗口,右侧时钟为子窗口。

使用4.4中的方案二,将浏览器子窗口在WMS申请的新窗口中显示。这样,在图形中可以看到有2个浏览器窗口信息,通过设置窗口的属性,强制子窗口为系统最顶层窗口。

按系统MENU键,弹出系统菜单(即第三方应用程序),此时,效果如下:

由上图可以看出,该方案能实现浏览器在图形中申请多个窗口,并实现第三方应用窗口夹在浏览器窗口中间。

4.6方案实现存在的问题

1.图形侧必须提供设置窗口z序的函数。

由于Android存在AMS、WMS两套服务管理activity和窗口,结构更负责,图层侧难度较大。

2.应用生命周期的问题

当其他应用出现在浏览器主Activity之前时,不论前面弹出了多少个浏览器的子窗口,浏览器的生命周期都进入onPause状态。

3.采用该方案开启4个全屏窗口后,图形buffer溢出,程序崩溃,崩溃信息如下

图形侧buffer申请失败。