在Android系统中,Activity窗口的大小是由WindowManagerService服务来计算的。WindowManagerService服务会根据屏幕及其装饰区的大小来决定Activity窗口的大小。一个Activity窗口只有知道自己的大小之后,才能对它里面的UI元素进行测量、布局以及绘制。本文将详细分析WindowManagerService服务计算Activity窗口大小的过程。
一般来说,Activity窗口的大小等于整个屏幕的大小,但是它并不占据着整块屏幕。为了理解这一点,我们首先分析一下Activity窗口的区域是如何划分的。
我们知道,Activity窗口的上方一般会有一个状态栏,用来显示3G信号、电量使用等图标,如图1所示。
图1 Activity窗口的Content区域示意图
从Activity窗口剔除掉状态栏所占用的区域之后,所得到的区域就称为内容区域(Content Region)。顾名思义,内容区域就是用来显示Activity窗口的内容的。我们再抽象一下,假设Activity窗口的四周都有一块类似状态栏的区域,那么将这些区域剔除之后,得到中间的那一块区域就称为内容区域,而被剔除出来的区域所组成的区域就称为内容边衬区域(Content Insets)。Activity窗口的内容边衬区域可以用一个四元组(content-left, content-top, content-right, content-bottom)来描述,其中,content-left、content-right、content-top、content-bottom分别用来描述内容区域与窗口区域的左右上下边界距离。
我们还知道,Activity窗口有时候需要显示输入法窗口,如图2所示。
图2 Activity窗口的Visible区域示意图
这时候Activity窗口的内容区域的大小有可能没有发生变化,这取决于它的Soft Input Mode。我们假设Activity窗口的内容区域没有发生变化,但是它在底部的一些区域被输入法窗口遮挡了,即它在底部的一些内容是不可见的。从Activity窗口剔除掉状态栏和输入法窗口所占用的区域之后,所得到的区域就称为可见区域(Visible Region)。同样,我们再抽象一下,假设Activity窗口的四周都有一块类似状态栏和输入法窗口的区域,那么将这些区域剔除之后,得到中间的那一块区域就称为可见区域,而被剔除出来的区域所组成的区域就称为可见边衬区域(Visible Insets)。Activity窗口的可见边衬区域可以用一个四元组(visible-left, visible-top, visible-right, visible-bottom)来描述,其中,visible-left、visible-right、visible-top、visible-bottom分别用来描述可见区域与窗口区域的左右上下边界距离。
在大多数情况下,Activity窗口的内容区域和可见区域的大小是一致的,而状态栏和输入法窗口所占用的区域又称为屏幕装饰区。理解了这些概念之后,我们就可以推断,WindowManagerService服务实际上就是需要根据屏幕以及可能出现的状态栏和输入法窗口的大小来计算出Activity窗口的整体大小及其内容区域边衬和可见区域边衬的大小。有了这三个数据之后,Activity窗口就可以对它里面的UI元素进行测量、布局以及绘制等 *** 作了。
从前面Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析一文可以知道,应用程序进程是从ViewRoot类的成员函数performTraversals开始,向WindowManagerService服务请求计算一个Activity窗口的大小的,因此,接下来我们就从ViewRoot类的成员函数performTraversals开始分析一个Activity窗口大小的计算过程,如图3所示。
图3 Activity窗口大小的计算过程
这个过程可以分为11个步骤,接下来我们就详细分析每一个步骤。
Step 1 ViewRootperformTraversals
这个函数定义在文件frameworks/base/core/java/android/view/ViewRootjava中,它的实现很复杂,一共有600-行,不过大部分代码都是用来计算Activity窗口的大小的,我们分段来阅读:
[java] view plaincopypublic final class ViewRoot extends Handler implements
ViewParent,
ViewAttachInfoCallbacks {
private void performTraversals() {
final View host = mView;
int desiredWindowWidth;
int desiredWindowHeight;
int childWidthMeasureSpec;
int childHeightMeasureSpec;
Rect frame = mWinFrame;
if (mFirst) {
DisplayMetrics packageMetrics =
mViewgetContext()getResources()getDisplayMetrics();
desiredWindowWidth = packageMetricswidthPixels;
desiredWindowHeight = packageMetricsheightPixels;
} else {
desiredWindowWidth = framewidth();
desiredWindowHeight = frameheight();
if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
windowResizesToFitContent = true;
}
}
复制代码
这段代码用来获得Activity窗口的当前宽度desiredWindowWidth和当前高度desiredWindowHeight。
需要在跳转的Intent对象中添加一个参数:
intentputExtra("comeFrom", activityName);跳转到目标activity时带上当前activity的名字,这样才知道是从哪里跳转进来的。
最近学习安卓开发activity的生命周期,对单个活动的生命周期较为熟悉。此时师兄抛出问题,当一个activity进入 onStop() 时,如何得知时由于用户点击了主页键,还是由于进入了另一个本程序的activity?
查阅网络资源后,得知可以通过安卓本身的多种方法来判断。不过某些方法的使用需要获取用户授权,或者需要较高版本的安卓系统。不过本文主要介绍通过activity本身的生命周期回调函数来判断。
由于设计两个activity的跳转,所以我们应该去考虑多个activity的生命周期回调函数顺序。查阅并测试可知,当进行activity跳转时,先执行原来activity的 onPause() 和,然后执行第二个activity的 onCreate() 、 onStart() 、 onResume() ,再执行第一个activity的 onStop 。如图所示,红色是第一个activity的回调函数执行,蓝色是第二个。
我们可以利用这个特点,通过一个static变量来记录当前run的activity数量,当这个数量为0的时候,即程序被压入后台,当这个数量不为0,则表明当前执行了一个跳转 *** 作。
首先新建一个 BaseActivity 类,声明一个static变量,让别的activity全部继承。并在 onStart() 和 onStop() 中修改 count 。
创建 MainActivity 类,继承自 BaseActivity 类,同时修改 onStop() ,检查 count 的值,判断此次导致 onStop() 的原因。我在这个activity中添加了一个button用于跳转到第二个activity。
这个类很简单,没有什么功能,只是跳转过来后,执行基类的 onCreate() 方法。
至此,我们便实现了通过activity生命周期回调函数判断是否被压入后台。不过,后来学长针对我的这种方式提出了漏洞——当引用外部SDK,且外部SDK中可以d出未继承我们自定义的base基类的activity,那么怎么处理这种情况呢?这里就要用到安卓SDK提供的全局生命周期类了——ApplicationregisterActivityLifecycleCallbaks,这里我们之后再谈。
当前的Activity只会有一个的
首先要知道Activity的四种状态:
Active/Runing 一个新 Activity 启动入栈后,它在屏幕最前端,处于栈的最顶端,此时它处于可见并可和用户交互的激活状态。
Paused 当 Activity 被另一个透明或者 Dialog 样式的 Activity 覆盖时的状态。此时它依然与窗口管理器保持连接,系统继续维护其内部状态,所以它仍然可见,但它已经失去了焦点故不可与用户交互。
Stoped 当 Activity 被另外一个 Activity 覆盖、失去焦点并不可见时处于 Stoped 状态。
Killed Activity 被系统杀死回收或者没有被启动时处于 Killed 状态。
protected void onStart() 该方法在 onCreate() 方法之后被调用,或者在 Activity 从 Stop 状态转换为 Active 状态时被调用,一般执行了onStart()后就执行onResume()。
protected void onResume() 在 Activity 从 Pause 状态转换到 Active 状态时被调用。
以上就是关于android 如何获取当前界面最上面的activity全部的内容,包括:android 如何获取当前界面最上面的activity、android开发问题:如何在当前Acitivity中用代码获取上一个Activity名称、安卓开发:如何得知当前activity是被压入后台,还是跳转到新的activity等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)