Android : Activity,Window and View.

    xiaoxiao2021-03-26  65

    看一下Activity是怎么通过View,Window等来用于自己的显示的。

    上图是Activity的Lifecycle。 这里只想说一下按back键和按home键退出,重新打开一个activity的时候的流程。 第一次冷启动流程是:onCreate()->onStart()->onResume() 按Home键退出时:onPause()->onStop() 重新打开时:onStart()->onResume() 按Back键退出时:onPause()->onStop()->onDestroy() 重新打开时:onCreate()->onStart()->onResume()

    1.entire lifetime : 这个生命周期发生在第一调用onCreate(Bundle)方法到最终的对onDestroy()的调用。一个Acitivity可以在onCreate()方法中对全局的状态进行初始化,在onDestroy中释放所有用到的资源。例如:如果需要一个后台运行的从网络中下载数据的线程,那么可以在onCreate()函数中进行创建,在onDestroy()中停止。

    2.visible lifetime: 可视期介于调用 onStart 与 onStop 之间。此时Activity是可见的,但是不能响应用户事件。一个Activity在其生命周期中是有可能经历多个可视期的。在非常极端的情况下,系统也有可能终止一个处于可视期的活动,这种情况很少见。onStop 方法通常用于暂时或者停止那些用来更新UI的动画,线程,定时器,服务等,所以当活动不可见的时占用的系统资源是很少的。当活动由不可见状态转化为可见状态时,在 onStart 中再启动相关的线程和服务。onStart 和 onStop 同样也用来注册和取消注册(unregister)那些用来更新UI的广播接收者。在活动不可见时我们需要取消注册接受者(Receivers),特别是那些支持目的动作(Intent)以及更新UI的接收者。这也是为什么在onCreate()中setContentView()之后界面不是马上可以看到的原因!!!这个部分还需要看~~

    3.foreground lifetime: 前台生命期从onResume()到onPause()。在这期间,这个activity在其他activity的前面,且正在与用户进行交互。一个activity可以很频繁的在Resumed与Paused状态之间进行切换。例如当设备Sleep时、一个Activity result被传递时、一个新的Intent被传递时等。所以为了有良好的用户体验,在 onResume 和 onPause 方法中的代码需要有更高的效率。foregroud的activity也可以在dumpsys meminfo里看到。

    Activity的创建过程:parseBaseApk()->parseBaseApplication()->parseActivity()->

    private Activity parseActivity(Package owner, Resources res, XmlPullParser parser, AttributeSet attrs, int flags, String[] outError, boolean receiver, boolean hardwareAccelerated) throws XmlPullParserException, IOException { ... Activity a = new Activity(mParseActivityArgs, new ActivityInfo()); ... }

    onResume()的过程:

    android.app.ActivityThread.performResumeActivity() ->android.app.Activity.performResume() ->android.app.Instrumentation.callActivityOnResume() ->com.sec.android.app.camera.Camera.onResume()

    上面这些Activity的初始化以及回调函数的注册过程后面再看。

    下面来看Activity和Window,View之间是什么关系,以及怎么利用View来画自己的界面的。 一个Activity可以画的部分,一般就是整个屏幕当中除了StatusBar以外的部分。

    一个Activity,可以有很多个View。这个可以在自己的res/layout目录下看到

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Hello World, MyActivity" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView"/> </LinearLayout>

    像这样的一个Layout,会被组织成下面这样阶梯状的Layout和View。

    这里的PRODUCT_POLICY是Android编译的时候指定的。有PhoneWindow和MIDWindow policy两种。一般都是用的PhoneWindow。 这个图里边可以看到一个Activity会有一个Window(或者说是PhoneWindow,Window类是个抽象类,PhoneWindow是Window类的唯一的实现类)。 总结几点就是:

    1.Activity用自己Window,有人说肯定只有一个,也有人说可以有多个,有待确认。总之Activity.attach()函数会嗲用mWindow = new PhoneWindow(this)这样创建一个PhoneWindow保存在Activity.mWindow中。

    2.之后Activity.setContentView()在getWindow().setContentView()会调用的PhoneWindow的setConteView(),在这里会检查是否有DecorView。如果没有就会调用installDecor()函数创建一个DecorView和mContentParent,然后把setContentView()传入的View或者layoutID转成View,都加到mContentParent当中(mLayoutInflater.inflate(layoutResID, mContentParent))。PhoneWindow都有一个叫DecorView的子类。DecorView又继承自FrameLayout。FrameLayout又继承自ViewGroup。ViewGroup继承自View。 DecorView是Activity持有的最顶层的一个唯一的View(也可以说是上面图的ViewGroup吧~)。PhoneWindow中的DecorView是整个界面包含ActioBar(statusbar除外),那layout里边用户定义的view是PhoneWindow里边的mContentParent。之所以这样应该是ActionBar和背景都是只画一次的。(可以看installDecor()->generateLayout()函数)。

    3.DecorView创建完需要加到WindowManager里的。这个过程可以看Activity里的setVisible()函数。这个函数内部调用了makeVisible()函数把DecorView加到WindowManager中。

    void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); }

    4.界面上的点击等操作是由WindowManagerService接收消息,然后回调 Activity函数来处理。

    什么时间点触发View画的流程?

    Activity创建完DecorView,会调用WindowManagerImpl.addView()。看上面makeVisible()函数。这最后会调用的ViewRootImpl.setView()函数。最终会调到requestLayout()函数等会调用scheduleTraversals()函数把TraversalRunnable注册到Choreographer.postCallback上面。

    mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

    也就是说ViewRootImpl不会自己触发画Frame的过程,而是把它加到Choreographier的CallbackQueue中(从postCallback函数看下去就可以找到postCallbackDelayedInternal函数中有这样的操作,但这里又去的是postCallbackDelayedInternal函数还会判断当前的Frame是不是已经超时,如果是的画,就直接scheduleFrameLocked来调用doFrame()而不会把Frame加到CallbackQueue当中)。

    这个流程可以看下面两张图,这两张图不准~~ 。 http://www.07net01.com/2015/07/866214.html

    Choreographier的doFrame会回调ViewRootImpl的performMeasure(),perforLayout(),performDraw()等函数,一层一层调用view的相关的函数去画好Surface。 这个与上面说的画的相符,就是ViewRoot开始,一层一层调用每个View的onDraw()函数把view的内容画上去(Canvas也是ViewRoot创建传下去的)。但onDraw()画上去之后不会马上从屏幕上看到,这个和Surfac,SurfaceFlinger相关。

    那Choreographer的doFrame是什么时间点开始的呢? doFrame是在Vsync信号来的时候调用。 Vsync信号是在FrameDisplayEventReceiver类继承了DisplayEventReceiver类来进行注册的,每次会注册下一个Vsync来的时候回调函数onVsync()。 这个注册过和回调的过程如下:

    http://www.csdn123.com/html/itweb/20131015/168825.htm

    下面看看每个View的onMeasure,onLayout,onDraw函数说明

    最后需要每个View负责把自己负责的正方型内的内容画上去。当然要先测量自己的正方形大小,然后给视图进行布局,也就是确定视图的正确的位置。最后就是画了。分别由下面的三个函数完成。

    onMeasure (int widthMeasureSpec, int heightMeasureSpec) { } onLayout (boolean changed,int left, int top,int rig , ht, int bottom) { } onDraw (Canvas canvas) { }

    下面的链接有比较好的说明,先不再赘述。 http://blog.csdn.net/guolin_blog/article/details/16330267

    上面说的画图流程都是画到Surface上面,那是怎么得到Surface的?

    上面说了View最终都会在ViewRootImpl.requestLayout()函数中请求把View的内容画到Surface上。 ViewRootImpl里边有一个成员变量mSurface就是保存Surface对象的,这个成员变量是通过WindowManagerService来申请的。

    应用程序进程请求WindowManagerService服务为一个应用程序窗口创建一个Surface对象;WindowManagerService服务请求SurfaceFlinger服务创建一个Layer对象,并且获得一个ISurface接口;WindowManagerService服务将获得的ISurface接口保存在其内部的一个Surface对象中,并且将该ISurface接口返回给应用程序进程;应用程序进程得到WindowManagerService服务返回的ISurface接口之后,再将其封装成其内部的另外一个Surface对象中。 最终获取Surface的地方在 WindowManagerService.relayoutWindow(....Surface outSurface) { ... SurfaceControl surfaceControl = winAnimator.createSurfaceLocked(); outSurface.copyFrom(surfaceControl);//这个就是创建的Surface!! ... }

    获取到的Surface,当然就是会保存在ViewRootImpl.mSurface这里了。

    获取完Surface之后,就可以利用Canvas去画了。

    final Canvas canvas; canvas = mSurface.lockCanvas(dirty);//dirty区域 canvas.setHighContrastText(attachInfo.mHighContrastText); ... mView.draw(canvas);//这里会跑去调用每个View的onDraw() ... surface.unlockCanvasAndPost(canvas);//交给RenderThread和OpenGL来画BufferQueue

    http://blog.csdn.net/luoshengyang/article/details/8303098

    http://blog.csdn.net/luoshengyang/article/details/7884628

    上面说已经用每层View的onDraw函数把Surface画好了??

    其实上面的surface.unlockCanvasAndPost(canvas);之前的内容也只是和Canvas相关,没有实际画到Surface上。或者说没有画到Surface的BufferQueue中。 真正用EGL处理Surface或者BufferQueue或者GraphicBuffer是在RenderThread里处理。 在Systrace里边可以看到RenderThread的DrawFrame其实就是frameworks/base/libs/hwui/rederthread/DrawFrameTask.cpp的run()函数。 调用顺序是:

    Surface.unlockCanvasAndPost() -> Surface.unlockAndPost() -> nHwuiDraw(mHwuiRenderer) -> android_view_Surface.cpp的draw() -> RenderProxy.cpp的syncAndDrawFrame()->DrawFrameTask.cpp的drawFrame()-> postAndWait()后面就是跑到run里边了

    doFrame包含dequeueBuffer(), queueBuffer(),eglSwapBuffersWithDamageKHR()等流程。 doFrame完了之后,APP这边的画界面的流程就完成了,eglSwapBuffersWithDamageKHR()之后就会交给SurfaceFlinger去把该画的内容给LCD了~~

    http://www.tuicool.com/articles/bEjYbqN http://androidperformance.com/2015/08/12/AndroidL-hwui-RenderThread-workflow.html

    在dequeueBuffer分配buffer时会调用到Gralloc.cpp的registerBuffer()函数。最终会跑到ionalloc.cpp的map_buffer函数最终用分配ion内存。

    SurfaceView比较特殊!!!

    SurfaceView是拥有自己画图空间的唯一的View。SurfaceView的存在是为了克服View画图的时间点是由ViewRoot决定的短板。SurfaceView在调用onDraw()的时候,会在自己需要画的位置保留一块透明的所谓punch hole。真正画这块内容是SurfaceView会利用SurfaceHolder和其他辅助线程。

    Canvas

    Canvas是对Bitmap或者Surface进行bit composition的。Canvas提供很多2D graphic API。这个不像OpenGL ES支持硬件加速。 Canvas使用Android 2D graphic library也就是skia。skia也是android的corecg,sgl,skiaagl等的基础。这里sgl是为了画2D graphic, skiaagl之前是为了3D Open GL的,但好像现在不再使用。 sgl使用的外部library有gif,jpeg,png,freetyp library等。

    OpenGL ES - 3D Graphics Library

    Android为了画3D图像使用OpenGL ES library。 EGL使用libagl.so(android GL)和libhgl.so(hardware GL)。下面是EGL Surface生成过程。

    mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, null); GLSurface sur = eglCreateWindowSurface(dpy, cnf, new EGLNativeWindowSurface(window), base); EGLNativeWindowSurface(const sp<Surface>& surface);

    activity viewroot window的关系

    SurfaceFlinger

    ActivityManager VS OOM

    待续..

    转载请注明原文地址: https://ju.6miu.com/read-650007.html

    最新回复(0)