Android : Activity,Window and View.

看一下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来申请的。
这里写图片描述

  1. 应用程序进程请求WindowManagerService服务为一个应用程序窗口创建一个Surface对象;
  2. WindowManagerService服务请求SurfaceFlinger服务创建一个Layer对象,并且获得一个ISurface接口;
  3. WindowManagerService服务将获得的ISurface接口保存在其内部的一个Surface对象中,并且将该ISurface接口返回给应用程序进程;
  4. 应用程序进程得到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

这里写图片描述

待续..

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值