当前位置:首页 » 安卓系统 » android窗口管理

android窗口管理

发布时间: 2023-01-18 18:40:18

A. Android 将App的内容延伸到状态栏/导航栏

来自我的CSDN博客: http://blog.csdn.net/dahaohan/article/details/52175190

看过Android的桌面应用都是介样的:

如何让自己的应用也达到这般效果呢?这里就介绍几种常用的方法以及它们之间的区别。

首先展示下此次demo的布局和初始状态:

初始效果图如下:

使用这个方式首先要理解几个概念,窗口层级以及窗口background/窗口透明:
Google在API-19 以及API-21新增对状态栏/导航栏窗口透明和颜色的控制:

对应的在主题内即可控制:

这里首先要明了这里状态栏和导航栏窗口是系统级窗口而Activity对应的时应用窗口,它们属于不同的窗口层级;
然后状态栏/导航栏系统级窗口是在App应用窗口之上,故而Activity应用窗口虽然有整个屏幕的大小,但是可显示内容的区域得除去其上叠加的不透明的窗口区域。详细的窗口计算绘制可参考大神老罗的博文:
Android窗口管理服务WindowManagerService计算Activity窗口大小的过程分析

下面来使用主题控制导航栏/状态栏透明,同时看看上述两种设置透明的方式效果有何不同:

初始桌面和启动Activity效果图:

可以看到虽然导航栏/状态栏透明了,当时应用窗口显示的内容依然只是除去了两个系统窗口之外的区域,并没有衍生到导航栏/状态栏之下。

效果如下:

可以看到已经将应用的内容布局延伸到导航栏/状态栏下方了,来看看关于android:windowTranslucentStatus
android:windowTranslucentNavigation的官方说明看看来理解其与设置color transparent的区别:

根据FLAG的说明,可以看出设置该标志位等同于View申请设置:

PS:从效果图看,虽然布局延伸到状态栏导航栏区域,但是相应的内容“hello world”文字也被状态栏/导航栏遮住了。在布局根视图设置fitsSystemWindows为true可以使得,系统自动为视图添加一个状态栏/导航栏高度的padding:

效果如下:

查看SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN的说明,可以发现其实还有两个非常接近的FLAG:

根据官方的说明提示,SYSTEM_UI_FLAG_FULLSCREEN / SYSTEM_UI_FLAG_HIDE_NAVIGATION主要用于动态切换隐藏/显示系统导航栏/状态栏;例如书籍阅读应用/视频播放应用等。而像游戏类的全屏应用则推荐使用window flag。

上述的透明导航栏/状态栏等API基本是需要API-19或是API-21才能使用的,这里还有一种API-1的方案能够实现布局内容全屏:

实际上只需要设置FLAG_LAYOUT_NO_LIMITS就足够了;这FLAG是看Android原生的Launcher / Keyguard源码,看到有用到如此设置,其窗口设置具体原理我也没有弄清..... 有大神了解可以指点下。

PS:这个套路下,使用fitsSystemWindows="true"是无效的,智能自己控制号布局位置。

B. 深入理解android2-WMS,控件

title: '深入理解android2-WMS,控件-图床版'
date: 2020-03-08 16:22:42
tags:
typora-root-url: ./深入理解android2-WMS-控件
typora--images-to: ./深入理解android2-WMS-控件

WMS主要负责两个功能, 一是负责窗口的管理,如窗口的增加删除,层级.二是负责全局事件的派发.如触摸点击事件.

先简单介绍几个重要的类

IWindowSession. 进程唯一的.是一个匿名binder.通过他向WMS请求窗口操作

surface 绘画时,canvas会把内容绘制到surface里.surface是有surfaceFlinger提供给客户端的.

WindowManager.LayoutParams 集成自ViewGroup.LayoutParams.用来指明client端的窗口的一些属性.最重要的是type. 根据这属性来对多个窗口进程ZOrder的排序.

windowToken.向WMS添加的窗口令牌.每个窗口都要有一个令牌.

IWindow. 是client提供给WMS的.继承自binder.WMS通过IWindow对象来主动发起client端的事件.

窗口的本周就是进行绘制所使用的surface,客户端向WMS添加窗口的过程,就是WMS为客户端分配surface的过程.

ui框架层就是使用surface上绘制ui元素.及响应输入事件

WMS负责surface的分配.窗口的层级顺序

surfaceFlinger负责将多个Surface混合并输出.

WMS有SystemServer 进程启动.他和AMS其实是运行于一个进程中的.只是分别有各自的线程.

上边传入了两个handler.这里就使用windowManager的handler来创建WMS.也就是在一个handerThread线程中创建

用来管理每个窗口的事件输入.也就是把输入事件转发到正确的窗口

能获取显示系统的同步信号.用来驱动动画的渲染

所有窗口动画的总管,在mChoreographer的驱动下渲染所有动画

只有PhoneWindowManager一个实现.定义了很多窗口相关的策略.是最重要的成员,比如负责窗口的zorder顺序.

zorder就是各个窗口在z轴的值.越大越在屏幕上层.窗口就是根据zorder值一层一层堆在一起.

可以绘制的屏幕列表.默认是只有1个.

管理所以窗口的显示令牌token,每个窗口都要属于一个token.这里的IBinder 是

表示所有Activity的token. AppWindowToken是WindowToken的子类,这个list的顺序和AMS中对mHistory列表中activity的顺序是一样的 .反应了系统中activity的叠加顺序.也就是说.所有窗口都有WindowToken.而Activity对应的窗口则多了AppWindowToken.

每个窗口都对应一个WindowState.存储改窗口的状态信息(这就和AMS中对每个activity抽象成ActivityRecord一样)

这里的iBinder 是IWIndow类.

Session 是WMS提供给客户端来与WMS进行交互的,这是匿名binder.为了减轻WMS的负担.客户端通过IWindowManager.openSession 拿到他的代理.然后通过代理与WMS交互.每个进程唯一.

客户端通过IWindowSession.add 来添加窗口. iWindowSession 是同aidl形成的.最终到了WMS.addWindow.

这里总的来说就是确立了客户窗口的WindowToken.WindowState.和DisplayContent. 并都保存了起来.同时根据layoutparams.type进行了些窗口等级的判断.

WindowToken将同一个应用组件的窗口安排在一起.一个应用组件可以是Activity,InputMethod.

WindowToken使应用组件在变更窗口时必须与自己的WindowToken匹配.

这里主要是为了处理窗口的层级关系而设立的.

只要是一个binder对象.都可以作为token向wms声明.wms会把这个binder对应起一个WindowToken.其实就是把客户端的binder和wms里的一个WindowToken对象进行了绑定.

因为Activity比较复杂,因此WMS为Activity实现了WindowToken的子类 appwindowtoken.同时在AMS启动Activity的ActivityStack.startActivityLocked里声明token.

然后在activityStack.realStartActivityLocked里在发给用户进程,然后用户在通过这个binder和WMS交互时带过来.

activity则在 activityStack 线程的handleResumeActivity 里把Activity 对应的窗口,加入到wMS中

取消token 也是在AMS中 ,也就是说, AMS负责avtivity的token向WMS的添加和删除.

当然.Activity的 r.appToken 是 IApplicationToken.Stub ,他里边有一系列的窗口相关的通知回调.

这里总结下. AMS在创建Activity的ActivityRecord时,创建了他的appToken,有把appToken传送给WMS.WMS对应匹配为APPWindowToken,最后还把这个appToken发送给activity.因此AMS就通过ActivityRecord就可有直接操作WMS对该窗口的绘制.如图.

每个window在WMS里都抽象成了WindowState.他包含一个窗口的所有属性.WindowState在客户端对应的则是iWidow.stub类.iWidow.stub有很多窗口通知的回调.

WindowState被保存在mWindowMap里.这是整个系统所有窗口的一个全集.

HashMap<IBinder, WindowToken> mTokenMap .这里是 IApplicationToken(客户端)和WindowToken的映射

HashMap<IBinder, WindowState> mWindowMap 这里是IWidow(客户端)和WindowState的映射,并且WMS通过这个IWindow 来回调客户端的方法.

上图可以看出.每个activity 只有一个ActivityRecord.也只有一个AppToken,也就只有一个WindowToken.而一个acitvity可能有多个窗口.每个窗口对应一个WindowState.

WindowToken用来和AMS交换. 而WindowState对应的iWindow则是WMS来与客户端交互的.

窗口显示次序就是窗口在Z轴的排了.因为窗口是叠加在一起的.因此就需要知道哪些显示在上边,哪些在下边.这个由WindowState构造时确定

可见.分配规则是由WindowManagerPolicy mPolicy来决定的.产生 mBaseLayer和mSubLayer. mBaseLayer决定该窗口和他的子窗口在所有窗口的显示位置. mSubLayer决定子窗口在同级的兄弟窗口的显示位置.值越高.显示约靠上.

WindowState 产生了他自己这个窗口的layer值后.在添加窗口的时候就会把所有窗口按layer排序插入mWindows列表中,在通过 adjustWallpaperWindowsLocked();进行层级调整.

当客户端通过IWindowsession.add后,客户端还没有获得Surface.只有在执行IWindowsession.relayout后.客户端才获得了一块Surface. IWindowsession.relayout根据客户端提供的参数,为客户端提供surface.具体实现是WMS.relayoutWindow

总的来说就是根据用户传入的参数,更新WindowState.然后遍历所有窗口布局.在设置合适的Surface尺寸,在返回给用户端

会循环调用6次.里边的逻辑大概如下

这里主要下,因为之前加了锁.requestTraversalLocked他又会重复执行();因此会重复循环执行布局.

布局这部分就记个原理吧

布局完成后.客户端的尺寸和surface都得到了.就可以绘制 了.WMS会通知客户端布局发送变化

总结,WMS 负责管理所有的窗口.包括系统窗口和APP窗口,而窗口必须有一个WindowToken所为标识符.同时WMS为每个窗口创建一个WindowState类,这是窗口在服务端的抽象.WindowState则绑定了一个客户端的IWindow类,WMS通过这个IWindow 向APP发送消息.

AMS在启动Activity的时候.把ActivityRecord.token 通过wms.addtoken 注册到WMS.又把这个token发送到APP端.因此三方可以通过这个token正确找到对应的数据.

WMS负责给所以窗口按ZOrder排序,确定窗口的尺寸,提供绘画用的surface.

Activity的窗口是先wms.addtoken 建立windowToken关系 . wms.addWindow. 添加串口, WMS.relayout获取surface. 完成 .

一个windowToken对应一个Activity. 但是可能对应多个windowSatate.也就是对应多个窗口.

是view树的根实现类是viewRootImpl.但是他不是view.他是用来和WMS进行交流的管理者.viewRootImpl内部有个IWindowSession,是WMS提供的匿名binder,同时还有个iWindow子类,用来让WMS给viewr发消息. view通过ViewRoot向WMS发消息.WMS在通过IWIndow 向APP发消息. 每个View树只有一个ViewRoot,每个Activity也只有一个ViewRoot. UI绘制,事件传递.都是通过ViewRoot.

.实现类是PhoneWindow . Activity和View的沟通就是通过Window.Activity实现window的各种回调.一个Activity也对应一个PhoneWindow.也对应一个View树.

Docerview 就是View树的根.这是一个View. 他由PhoneWindow管理. 下文的WindowManager也由phoneWindow管理.

他还管理window的属性 WindowManager.layoutparams.

他是一个代理类.他集成自ViewManager.他的实现是WindowManagerImpl.这是每个Activity都有一个.但是他只是把工作委托给了 WindowManagerGlobal来实现. 他负责添加删除窗口,更新窗口.并控制窗口的补件属性WindowManager.Layoutparams.

是进程唯一的.负责这个进程的窗口管理.他里边有三个集合.保存这个进程所有窗口的数据.这里的每个数据根据index得到的是同一个Activity属性.所有的WindowManager的操作都转到他这里来.

private final ArrayList<View> mViews 每个view是个跟节点

private final ArrayList<ViewRootImpl> mRoots view对应的viewRoot

private final ArrayList<WindowManager.LayoutParams> mParams 窗口的layoutparams属性.每个窗口一个

对于一个acitivity对象永远对应一个PhoneWindow,一个WindowManagerImpl,一个WMS端的APPWindowToken,一个AMS里的ActivityRecord(但是如果一个activity在栈里有多个对象,就有多个ActivityRecord和AppWindowToken),acitvity 的默认窗口的view树是DocerView.

一个窗口 对应一个ViewRoot,一个View树.一个WindowManager.LayoutParams,一IWindow(WMS回调app).一个WSM端的WindowSatate.

但是一个Activity可以有多个窗口,因此对应WMS里可能有多个WindowSatate.这些WindowState都对应一个AppWindowToken.

一个Activity可能被加载多次.因此在AMS中可能有多个ActivityRecord对应这个activit的多个对象.

但是一个进程则对应一个WindowManagerGlobal.一个ActivityThread(主线程).一个ApplicationThread(AMS调用app).一个iWindowSession(viewroot向WMS发消息)

这里的区别就是 app与AMS 的交互是以进程之间进行通信.而App与WMS的交互.则是以窗口作为通信基础.

当Activity由AMS启动时.ActivityThread 通过handleResumeActivity执行resume相关的操作.这个函数首先是执行activity.resume, 此时activity 对应的view树已经建立完成(oncreate中建立,PhoneWindow也创建了).需要把activity的窗口添加到WMS中去管理.

这里的wm是WindowManager.是每个activity一个.他内部会调用WindowManagerGlobal.addView

WindowManagerGlobal.addView

这里会为窗口创建ViewRootImpl. 并把view.ViewRootImpl.WindowMa.LayoutParams都保存在WindowManagerGlobal中, 并通过ViewRootImpl向WMS添加窗口

如果这个窗口是子窗口(wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW)

就把子窗口的token设为父窗口的token否则就是所属activity的token.

在来个图

在这里我们看到.我们通过mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 拿到的并不是远程的WMS.而是本地的WindowManagerImpl. 他又把请求转发给WindowManagerGlobal ,而WindowManagerGlobal作为进程单实例.又是吧请求转给对应窗口的ViewRootImpl.ViewRootImpl通过WMS的IWindowSession 把数据发给WMS.

ViewRootImpl用来沟通View和WMS.并接受WMS的消息.这是双向的binder通信.作为整个空间树的根部,控件的测量,布局,绘制,输入时间的派发都由ViewRootImpl来触发.

ViewRootImpl由WindowManagerGlobal创建,是在activityThread.handleResumeActivity时,先执行activity.resume.在调用wm.addView. 就会执行WindowManagerGlobal.addView里.创建ViewRootImpl,此时是在ui线程中.

ViewRootImpl里的mView属性.host属性,就是view树

添加窗口时通过requestLayout();向ui线程发送消息.最后回调到ViewRootImpl.performTraversals.他是整个ui控件树,measure.layout.draw的集合.

这里分为五个阶段.

预测量阶段.进行第一次测量,获得view.getMeasuredWitdh/Height,此时是控件树期望的尺寸.会执行View的onMeasure

布局阶段,根据预测量的结果,通过IWindowSession.relayout向WMS请求调整窗口的尺寸这会使WMS对窗口重新布局,并把结果返回给ViewRootImpl.

最终测量阶段, 预测量的结果是view树期望的结果.WMS可能会进行调整,在这里WMS已经把结果通知了ViewRootImpl.因此这里会窗口实际尺寸performTraversals进行布局.view及子类的onMeasure会被回调

布局阶段. 测量完成后获得空间的尺寸,布局要确定控件的位置,View及子类的onLayout会被回调.

绘制阶段,使用WMS提供的surface.进行绘制,View及子类的onDraw会被回调.

通常我们看到的都是 先measure,在layout在draw. 这里看到.其实measure先得到期望值,在和WMS沟通.WMS在调整后,返回确定值,在根据确定值进行mesure.

measureHierarchy里会通过三次协商.执行performMeasure 来确认合适的尺寸.

performMeasure 会调用view 的measure 优会调用onMeasure. 我们可重写onMeasure来实现测量.而measure 方法是final的.onMeasure 的结果通过setMeasuredDimension方法保存.

对于view. onMeasure.比较容易. 对于ViewGroup.则还要遍历调用他所以子view的measure. 并且需要考虑padding和子view 的margin. padding是控件外内边距. margin 是控件外边距.

ViewGroup需要先测量完子view.在根据子view的测量值得到自己的宽高.举例,如果只有一个子view.那么ViewGroup的宽= 子view的宽+子view的margin+viewg的padding. 至少是这个值.

继续回到performTraversals

这里就是提前测量了一下.得到控件树希望的尺寸大小,

通过relayoutWindow来布局窗口. ViewRootImpl 通过IWindowSession 来通知WMS进行窗口布局.

这里主要下. 调用WMS后.WMS会调整窗口的尺寸. 同时会生成surface返回给ViewRootImpl. 因此后续的绘画就有了画布了.可以看到最后的参数是mSurface.这是本地的surface. 这里会和wms的进行绑定.

接下来继续performTraversals,绑定WMS返回的surface.然后更新尺寸.

最后进行最终测量. 上边过程太乱了. 了解下就行.还是看常见的控件绘制流程.

绘制由viewRootImpl.performTraversals触发, 抽取出来后,就是这样

就是直接调用view树的根的measure方法. 传入到View

该方法是final .意味着无法重写.这里又会调用onMeasure.

因此.对于view.在onMeasure中调整好高度,通过setMeasuredDimension设置好自己的测量宽高就可以了.

对应ViewGroup.则在onMeasure中,先要遍历子view.调用他们的measure(注意一定是调用子类的measure,measure又会调用onMeasure), 子view宽高都知道后,在根据子view的宽高来设置自己.也就是ViewGroup的宽高受子view影响.

可以看到view的measure又调用了onMeasure, 如果是view 则可以直接重新onMeasure来设定大小.而对于ViewGroup, 则需要重写onMeasure来先遍历子view.设定大小.然后再设定viewGroup的大小. ViewGroup并没有重写onMeasure.因为每个ViewGroup要实现的效果不同,需要自己完成.但ViewGroup提供了几个方法供ViewGroup的继承类来遍历子view.

view的宽高由自己的layoutParams和父view提供的 widthMeasureSpec|heightMeasureSpec共同决定.

View 自己的宽高,是保存在LayoutParams中对,以宽举例 LayoutParams.width 有三种情况,精确值(就是指定大小),MATCH_PARENT. WRAP_CONTENT,模式则有fuview提供.有 unspecified,exactly,at_most三种.

匹配如下.

其实这个很好理解. 如果子view自己指定了宽高.就用他的值就可以.如果子view是match_parent.那就使用父view提供的宽高. 如果子view是wrap_content,那就不能超过父view的值.

看下ViewGroup为子view绘制而提供的方法,可以看到.ViewGroup会减去padding和margin,来提供子view的宽高.

上步measure过程未完成后,整个view书的 测量宽高都得到了.也就是view.getMeasuredWidth()和getMeasuredHeight()

performLayout中会调用mView.layout. 这样就把事件从ViewRootImpl传递到了view.而layout中又会调用onLayout.ViewGroup需要重写onLayout为子view进行布局,遍历调用子view的layout.因此就完成整个view树的laylut过程.

竖向的实现, 竖向的就行把view从上到下一次排开

这里注意区分.measure过程是先得到子view的测量值,在设定父ViewGroup的值.而layout过程则是先传入父view的左上右下值,来计算子view的左上右下的位置值.这里应该具有普遍性.但不知道是否绝对.

performDraw 中的调用draw.又调用mView.draw.然后就进入view树的绘制了.

view的draw 又会调用onDraw ,viewGroup又调用dispatchDraw()把draw分发到子view里 绘制的画布就是canvas. 这是从surface.lockCanvas中获得的一个区域.

而在ViewGroup.dispatchDraw中.重要的一点是getChildDrawingOrder 表示子view的绘制顺序.默认是与ziview的添加顺序一样.我们也可以改变他.最后绘制的会显示在最上边,而这也影响view的事件传递顺序.

view.draw. 就是一层一层的画内容.先画北京,在onDraw.在画装饰什么的.

canvas.translate(100,300)通过平移坐标系.使之后的内容可以直接在新坐标系中绘制.

这就是ViewGroup在向子view传递canvas的时候.方便多了. 会之前先对其ziview的左上角.那么子view就可以直接从自己坐标轴的(0,0)开始绘制, 绘制完成后ViewGroup在还原原有坐标系.

canvas.save. canvas.restore 用来保存还原坐标系.

view.invalidate.

当某个view发送变化需要重绘时,通过view.invalidate向上通知到ViewRootImpl.从这个view到ViewRootImpl的节点都标记为藏区域.dirty area. ViewRootimpl再次从上到下重绘时,只绘制这些脏区域.效率高.

本来安卓兼容使用键盘,也支持,触摸.二者的输入事件派发不一样.使用键盘时会有个控件处于获得焦点状态.处于触摸模式则由用户决定. 因此控件分为两类.任何情况下都能获得焦点.如输入文本框.只有在键盘操作时才能获得焦点.如菜单,按钮.

安卓里有触摸模式.当发送任意触摸时进入触摸模式.当发送方向键和键盘或者执行View.requestRocusFromTouch时,退出触摸模式.

获取焦点. view.request.

先检查是否能获取焦点,

然后设置获取简单的标记,

上传递到ViewRootimpl.保证只能有一个控件获取焦点.

通知焦点变化的监听者.

更新view的drawable状态,

requestChildFocus会把焦点事件层层上报取消原来有焦点的控件.最后的效果就是从viewrootimpl中.到最终有焦点的view.构成一条 mFoucued 标识的链条.来个图就明白了.每个view的mFocused总是指向他的直接下级.

获取focus的传递是从底层view到顶层的ViewRootImpl.而取消focus测试从顶层的ViewRootimpl到底层原来那个获得焦点的view.

而如果是ViewGroup请求获取焦点,会根据FLAG_MASK_FOCUSABILITY特性来做不同方式,分别有先让自己获取焦点,或者安卓view的索引递增或者递减来匹配view.

ViewRootImpl 中的.WindowInputEventReceiver接受输入事件.他会把事件包装成一个QueuedInputEvent.然后追加到一个单链表的末尾.接着重头到尾的处理输入事件,并通过deliverInputEvent完成分发.这里会把单链表所有事件都处理完.

deliverInput中又会把触摸事件执行到通过 ViewPreImeInputStage.processKeyEvent. 转入mView.dispatchPointerEvent(event).这里又进入 dispatchTouchEvent

MotionEvent是触摸事件的封装.getAction可以拿到动作的类型和触控点索引号.

getX(),getY().拿到动作的位置信息.通过getPointID拿到触控点的id. 动作以down 开头.跟多个move.最后是up.

,当事件返回true.表示事件被消费掉了.

C. Android四大组件 —— Activity(窗口)

Activity是一个 界面 的载体,可以把它与html页面进行类比,html页面由各种各样的标签组成,而Activity则可以由 各种控件 组成。

Activity的掌握重点主要在于:

     a.Activity的生命周期 

     b.Activity的启动模式

              onCreate() : 

            当Activity第一次被创建的时候调用此方法.一般在此方法中 进行控件的声明,添加事件等初始化工作 .

            onStart():

            当Activity被显示到屏幕上的时候调用此方法,执行完此方法后 界面可见

            onResume():

            当此Activity能够被操作之前,也就是能够获得用户的焦点之前调用此方法.

            onRestart():

            当Activity被停止后又被再次启动之前调用此方法.接着将调用onStart()方法.

            onPause():

            当第一个Activity通过Intent启动第二个Activity的时候,将调用第一个Activity的onPause()方法.然后调用第二个Activity的onCreate(),onStart(),onResume()方法,接着调用第一个Activity的onStop()方法.如果Activity重新获得焦点,则将调用onResume()方法;如果此Activity进入用户不可见状态,那么将调用onStop()方法.

            onStop():

            当第一个Activity被第二个Activity完全覆盖,或者被销毁的时候回调用此方法.如果此Activity还会与用户进行交互,将调用onRestart方法();如果此Activity将被销毁,那么将调用onDestroy()方法.

            注意:

              a.home键返回,锁屏,关闭界面肯定会调用onStop方法

              b.但是开启另一个Activity并不一定会调用onStop方法

            onDestroy():

               Activity被销毁之前调用此方法.或者是调用finish()方法结束Activity的时候调用此方法.可以在此方法中进行收尾工作,比如释放资源等.

             Active/Runing 一个新 Activity 启动入栈后,它在屏幕最前端,处于栈的最顶端,此时它处于可见并可和用户交互的激活状态。

             Paused  当 Activity 被另一个透明或者 Dialog 样式的 Activity 覆盖时的状态。此时它依然与窗口管理器保持连接,系统继续维护其内部状态,所以它仍然可见,但它已经失去了焦点故不可与用户交互。

             Stoped  当 Activity 被另外一个 Activity 覆盖、失去焦点并不可见时处于  Stop ed 状态。

             Killed  Activity 被系统杀死回收或者没有被启动时处于  Killed 状态。

            在 manifest 文件中声明 activity 时,利用activity元素的 launchMode 属性来设定 activity 与 task 的关系。

launchMode 属性 指明了 activity 启动 task 的方式,默认 standard方式

             standard(默认模式):

          系统在启动 activity 的 task 中创建一个新的 activity 实例,并把 intent 传送路径指向它。 该 activity 可以被实例化多次,各个实例可以属于不同的 task,一个 task 中也可以存在多个实例。

             singleTop:

           如果 activity 已经存在一个实例并位于当前 task 的 栈顶 ,则系统会调用已有实例的 onNewIntent() 方法把 intent 传递给已有实例,而不是创建一个新的 activity 实例。activity 可以被实例化多次,各个实例可以属于不同的 task,一个 task 中可以存在多个实例(但仅当 back stack 顶的 activity 实例不是该 activity 的)。

               singleTask:

            系统将创建一个新的 task,并把 activity 实例 作为根 放入其中。但是,如果 activity 已经在其它 task 中存在实例,则系统会通过调用其实例的onNewIntent() 方法把 intent 传给已有实例,而不是再创建一个新实例。 此 activity 同一时刻只能存在一个实例。

            例如:可以用于关闭所有Activity或重新登录等

             singleInstance:

            除了系统不会把其它 activity 放入当前实例所在的 task 之外,其它均与"singleTask"相同。activity 总是它所在 task 的唯一成员;它所启动的任何 activity 都会放入其它 task 中

            主要是startActivity(intent),或者带值返回startActivityForResult(intent) , Activity的跳转方式  。

D. android 怎么让浮动窗口显示

你好,
android 手机让浮动窗口显示的设置步骤:
点击设置图标
点击“设置”列表中“管理应用程序”
找到要设置浮动窗口的软件
进入“应用程序信息”
点击“应用程序信息”最下面的“权限”
在“权限”页面中勾选“显示悬浮窗”。这样就开启了浮动窗
android手机版本繁多,各个厂家的rom不一样,设置也不一样。

E. 安卓浏览器看不到左侧框架

首先找到view,然后点击。
看到tool-Windows,将鼠标放上,你将会看到project,然后点击,左侧栏就可以出现了。
窗口管理是android的一个核心内容。它管理着窗口的创建和销毁,布局和大小,焦点的控制等等。窗口可以分为两类:一种是应用窗口,即由具体应用创建的窗口,其实其中还可以细分出父窗口和子窗口。窗口一般都会对应一个activity。一种是系统窗口,如状态栏,这类窗口由系统直接通过windowManager来创建,和activity无关。

热点内容
java小数正则表达式 发布:2025-05-20 11:30:58 浏览:136
文件夹加密win7 发布:2025-05-20 11:27:46 浏览:837
压缩文件设置密码有什么意思 发布:2025-05-20 11:26:37 浏览:551
造梦西游qq登录如何修改密码 发布:2025-05-20 11:18:36 浏览:382
淘宝缓存清理后还是大 发布:2025-05-20 11:15:39 浏览:149
ios云存储自动订购 发布:2025-05-20 11:06:22 浏览:110
编程与数学 发布:2025-05-20 11:01:23 浏览:444
asp连接远程数据库 发布:2025-05-20 10:50:20 浏览:390
一般电脑配置哪个好 发布:2025-05-20 10:40:58 浏览:604
我的世界撸树服务器 发布:2025-05-20 10:33:37 浏览:742