Android Activity是怎么画出来的

来源:互联网 发布:mac怎么装正版office 编辑:程序博客网 时间:2024/04/30 12:26

Activity是在onResume里显示出来的,下面看下具体的流程。

 

ActivityThread.java

    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {// ...           if (r.window == null && !a.mFinished && willBeVisible) {                r.window = r.activity.getWindow();                View decor = r.window.getDecorView();                decor.setVisibility(View.INVISIBLE);                ViewManager wm = a.getWindowManager();                WindowManager.LayoutParams l = r.window.getAttributes();                a.mDecor = decor;                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;                l.softInputMode |= forwardBit;                if (a.mVisibleFromClient) {                    a.mWindowAdded = true;                    wm.addView(decor, l); //关键                }//...}

关键的函数是wm.addView,这个wm是啥呢?

ViewManager.java中可以看到,就是一接口,那肯定要找到实现他的类,搜索下发现是WindowManager.java,可是这货里也没有具体的,继续找实现Windomanager的家伙。

最后可以找到实际是WindowManagerImpl.java实现了这个方法。

WindowManagerImpl.java

  

  private void addView(View view, ViewGroup.LayoutParams params, boolean nest)    {    //...            root = new ViewRoot(view.getContext());            root.mAddNesting = 1;            view.setLayoutParams(wparams);                        if (mViews == null) {                index = 1;                mViews = new View[1];                mRoots = new ViewRoot[1];                mParams = new WindowManager.LayoutParams[1];            } else {                index = mViews.length + 1;                Object[] old = mViews;                mViews = new View[index];                System.arraycopy(old, 0, mViews, 0, index-1);                old = mRoots;                mRoots = new ViewRoot[index];                System.arraycopy(old, 0, mRoots, 0, index-1);                old = mParams;                mParams = new WindowManager.LayoutParams[index];                System.arraycopy(old, 0, mParams, 0, index-1);            }            index--;            mViews[index] = view;            mRoots[index] = root;            mParams[index] = wparams;        }        // do this last because it fires off messages to start doing things        root.setView(view, wparams, panelParentView);}


如果不深究里面每一句话的意思,大体上看来就是new了一个ViewRoot,然后把各种参数传入,调用它的setView方法。

这里我们有必要看一下ViewRoot,这货虽然看上去是个View穷屌丝,其实是个高帅富:

ViewRoot.java

public final class ViewRoot extends Handler implements ViewParent,
        View.AttachInfo.Callbacks {

看这声明,原来本体就是个handle,实现了一些方法。

看下里面的成员变量,比较关键的是

    static IWindowSession sWindowSession;

    private final Surface mSurface = new Surface();
看看他的构造函数:

    public ViewRoot(Context context) {        super();        if (MEASURE_LATENCY && lt == null) {            lt = new LatencyTimer(100, 1000);        }        // For debug only        //++sInstanceCount;        // Initialize the statics when this class is first instantiated. This is        // done here instead of in the static block because Zygote does not        // allow the spawning of threads.        getWindowSession(context.getMainLooper());                mThread = Thread.currentThread();        mLocation = new WindowLeaked(null);        mLocation.fillInStackTrace();        mWidth = -1;        mHeight = -1;        mDirty = new Rect();        mTempRect = new Rect();        mVisRect = new Rect();        mWinFrame = new Rect();        mWindow = new W(this, context);        mInputMethodCallback = new InputMethodCallback(this);        mViewVisibility = View.GONE;        mTransparentRegion = new Region();        mPreviousTransparentRegion = new Region();        mFirst = true; // true for the first time the view is added        mAdded = false;        mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);        mViewConfiguration = ViewConfiguration.get(context);        mDensity = context.getResources().getDisplayMetrics().densityDpi;    }


通过getWindowSession方法得到了Session的本地代理IWindowSession,并保存在变量sWindowSession中

  

    public static IWindowSession getWindowSession(Looper mainLooper) {        synchronized (mStaticInit) {            if (!mInitialized) {                try {                    InputMethodManager imm = InputMethodManager.getInstance(mainLooper);                    sWindowSession = IWindowManager.Stub.asInterface(                            ServiceManager.getService("window"))                            .openSession(imm.getClient(), imm.getInputContext());                    mInitialized = true;                } catch (RemoteException e) {                }            }            return sWindowSession;        }    }


这里简单的说下,

IWindowManager.Stub.asInterface(
                            ServiceManager.getService("window"));

就是通过ServiceManager得到windowManagerService的本地代理,并通过这个本地代理来调用远程WMS的方法openSession,返回Session对应的本地代理对象IWindowSession。

而 一开始的    private final Surface mSurface = new Surface();调用了无参的构造函数,实际上没有干啥活,当前的surface是无效的。

    public Surface() {        if (DEBUG_RELEASE) {            mCreationStack = new Exception();        }        mCanvas = new CompatibleCanvas();    }

接着继续看setView();

    public void setView(View view, WindowManager.LayoutParams attrs,            View panelParentView) {//...                requestLayout();                mInputChannel = new InputChannel();                try {                    res = sWindowSession.add(mWindow, mWindowAttributes,                            getHostVisibility(), mAttachInfo.mContentInsets,                            mInputChannel);                } catch (RemoteException e) {                    mAdded = false;                    mView = null;                    mAttachInfo.mRootView = null;                    mInputChannel = null;                    unscheduleTraversals();                    throw new RuntimeException("Adding window failed", e);                } finally {                    if (restore) {                        attrs.restore();                    }                }//...}


requestLayout()和sWindowSession.add方法是最关键的。我们分别来看。

requestLayout只是给ViewRoot的handle发送DO_TRAVERSAL消息,handle收到消息后,会调用performTraversals()

这个方法巨长无比,简直不忍直视,我们主要是看和surface的联系,就挑着看。

    private void performTraversals() {      relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);      draw(fullRedrawNeeded);}

 

 

 

看看relayoutWindow(),这个方法里对surface有了重新的赋值:

    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,            boolean insetsPending) throws RemoteException {        float appScale = mAttachInfo.mApplicationScale;        boolean restore = false;        if (params != null && mTranslator != null) {            restore = true;            params.backup();            mTranslator.translateWindowLayout(params);        }        if (params != null) {            if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);        }        mPendingConfiguration.seq = 0;        //Log.d(TAG, ">>>>>> CALLING relayout");        int relayoutResult = sWindowSession.relayout(                mWindow, params,                (int) (mView.mMeasuredWidth * appScale + 0.5f),                (int) (mView.mMeasuredHeight * appScale + 0.5f),                viewVisibility, insetsPending, mWinFrame,                mPendingContentInsets, mPendingVisibleInsets,                mPendingConfiguration, mSurface);        //Log.d(TAG, "<<<<<< BACK FROM relayout");        if (restore) {            params.restore();        }                if (mTranslator != null) {            mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);            mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);            mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);        }        return relayoutResult;    }

实际通过Session的本地代理Binder  sWindowSession来调用了远程的方法:

WindowManagerService.java

       public int relayout(IWindow window, WindowManager.LayoutParams attrs,                int requestedWidth, int requestedHeight, int viewFlags,                boolean insetsPending, Rect outFrame, Rect outContentInsets,                Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {            //Log.d(TAG, ">>>>>> ENTERED relayout from " + Binder.getCallingPid());            int res = relayoutWindow(this, window, attrs,                    requestedWidth, requestedHeight, viewFlags, insetsPending,                    outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface);            //Log.d(TAG, "<<<<<< EXITING relayout to " + Binder.getCallingPid());            return res;        }

这里把传入的surface叫做outSruface是别有深意的。

继续分析

    public int relayoutWindow(Session session, IWindow client,            WindowManager.LayoutParams attrs, int requestedWidth,            int requestedHeight, int viewVisibility, boolean insetsPending,            Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,            Configuration outConfig, Surface outSurface) {//...            WindowState win = windowForClientLocked(session, client, false);//...                try {                    Surface surface = win.createSurfaceLocked();                    if (surface != null) {                        outSurface.copyFrom(surface);//通过windowState来创建一个新的surface并返回给传入的surface,这样surface和native的surface就联系起来了。                        win.mReportDestroySurface = false;                        win.mSurfacePendingDestroy = false;                        if (SHOW_TRANSACTIONS) Slog.i(TAG,                                "  OUT SURFACE " + outSurface + ": copied");                    } else {                        // For some reason there isn't a surface.  Clear the                        // caller's object so they see the same state.                        outSurface.release();                    }                } catch (Exception e) {                    mInputMonitor.updateInputWindowsLw();                                        Slog.w(TAG, "Exception thrown when creating surface for client "                             + client + " (" + win.mAttrs.getTitle() + ")",                             e);                    Binder.restoreCallingIdentity(origId);                    return 0;                }//...}

relayoutWindow中首先是取出了Clinet对应的windowstate对象,通过他去调用createSurfaceLocked,并返回给传入的surface,到这里,ViewRoot里的mSurface就有了灵魂!

每一个Client都有唯一的一个windowstate对象。ViewRoot-mWindow------WindowState都是一一对应的关系,这个对象是什么时候被创建的? 下面会降到

接下来继续分析createSurfaceLocked

        Surface createSurfaceLocked() {//......                try {                    mSurface = new Surface(                            mSession.mSurfaceSession, mSession.mPid,                            mAttrs.getTitle().toString(),                            0, w, h, mAttrs.format, flags);                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  CREATE SURFACE "                            + mSurface + " IN SESSION "                            + mSession.mSurfaceSession                            + ": pid=" + mSession.mPid + " format="                            + mAttrs.format + " flags=0x"                            + Integer.toHexString(flags)                            + " / " + this);                } catch (Surface.OutOfResourcesException e) {                    Slog.w(TAG, "OutOfResourcesException creating surface");                    reclaimSomeSurfaceMemoryLocked(this, "create");                    return null;                } catch (Exception e) {                    Slog.e(TAG, "Exception creating surface", e);                    return null;                }//......}

在这里调用了surface的有参的构造函数

surface.java

    /**     * create a surface with a name     * {@hide}     */    public Surface(SurfaceSession s,            int pid, String name, int display, int w, int h, int format, int flags)        throws OutOfResourcesException {        if (DEBUG_RELEASE) {            mCreationStack = new Exception();        }        mCanvas = new CompatibleCanvas();        init(s,pid,name,display,w,h,format,flags);        mName = name;    }


和无参的不一样,这里调用了native的init

android_view_surface.cpp

static void Surface_init(        JNIEnv* env, jobject clazz,         jobject session,        jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jint flags){    if (session == NULL) {        doThrow(env, "java/lang/NullPointerException");        return;    }        SurfaceComposerClient* client =            (SurfaceComposerClient*)env->GetIntField(session, sso.client);//获取出session中的SurfaceComposerClient对象,这个对象是怎么来//的?下文会讲到    sp<SurfaceControl> surface;    if (jname == NULL) {        surface = client->createSurface(pid, dpy, w, h, format, flags);//调用SurfaceComposerClient方法,创建一个SurfaceControl对象,该对//象封装了Isurface和SurfaceComposerClient的一些方法,方便Client调用    } else {        const jchar* str = env->GetStringCritical(jname, 0);        const String8 name(str, env->GetStringLength(jname));        env->ReleaseStringCritical(jname, str);        surface = client->createSurface(pid, name, dpy, w, h, format, flags);    }    if (surface == 0) {        doThrow(env, OutOfResourcesException);        return;    }    setSurfaceControl(env, clazz, surface);//保存surfacecontrol对象}

surfacecomposerclient和surfaceflinger的关系比较复杂,后面会另写blog来讲。

到这里surface就在native空间有了对应的surfacecontrol,就可以通过surfacecontrol来调用surfacefilnger的方法了。

回到Viewroot,接下来就是draw()方法

    private void draw(boolean fullRedrawNeeded) {        Surface surface = mSurface;        if (!dirty.isEmpty() || mIsAnimating) {            Canvas canvas;//画布            try {                int left = dirty.left;                int top = dirty.top;                int right = dirty.right;                int bottom = dirty.bottom;                canvas = surface.lockCanvas(dirty);//surface锁定画布并返回,然后在canvas上画出各种元素                if (left != dirty.left || top != dirty.top || right != dirty.right ||                        bottom != dirty.bottom) {                    mAttachInfo.mIgnoreDirtyState = true;                }                // TODO: Do this in native                canvas.setDensity(mDensity);            } catch (Surface.OutOfResourcesException e) {                Log.e(TAG, "OutOfResourcesException locking surface", e);                // TODO: we should ask the window manager to do something!                // for now we just do nothing                return;            } catch (IllegalArgumentException e) {                Log.e(TAG, "IllegalArgumentException locking surface", e);                // TODO: we should ask the window manager to do something!                // for now we just do nothing                return;            }            try {                if (!dirty.isEmpty() || mIsAnimating) {                    long startTime = 0L;                    if (DEBUG_ORIENTATION || DEBUG_DRAW) {                        Log.v(TAG, "Surface " + surface + " drawing to bitmap w="                                + canvas.getWidth() + ", h=" + canvas.getHeight());                        //canvas.drawARGB(255, 255, 0, 0);                    }                    if (Config.DEBUG && ViewDebug.profileDrawing) {                        startTime = SystemClock.elapsedRealtime();                    }                    // If this bitmap's format includes an alpha channel, we                    // need to clear it before drawing so that the child will                    // properly re-composite its drawing on a transparent                    // background. This automatically respects the clip/dirty region                    // or                    // If we are applying an offset, we need to clear the area                    // where the offset doesn't appear to avoid having garbage                    // left in the blank areas.                    if (!canvas.isOpaque() || yoff != 0) {                        canvas.drawColor(0, PorterDuff.Mode.CLEAR);                    }                    dirty.setEmpty();                    mIsAnimating = false;                    mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();                    mView.mPrivateFlags |= View.DRAWN;                    if (DEBUG_DRAW) {                        Context cxt = mView.getContext();                        Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +                                ", metrics=" + cxt.getResources().getDisplayMetrics() +                                ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());                    }                    int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);                    try {                        canvas.translate(0, -yoff);                        if (mTranslator != null) {                            mTranslator.translateCanvas(canvas);                        }                        canvas.setScreenDensity(scalingRequired                                ? DisplayMetrics.DENSITY_DEVICE : 0);                        mView.draw(canvas);//调用传入decorView的draw方法                    } finally {                        mAttachInfo.mIgnoreDirtyState = false;                        canvas.restoreToCount(saveCount);                    }                    if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {                        mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);                    }                    if (SHOW_FPS || Config.DEBUG && ViewDebug.showFps) {                        int now = (int)SystemClock.elapsedRealtime();                        if (sDrawTime != 0) {                            nativeShowFPS(canvas, now - sDrawTime);                        }                        sDrawTime = now;                    }                    if (Config.DEBUG && ViewDebug.profileDrawing) {                        EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);                    }                }            } finally {                surface.unlockCanvasAndPost(canvas);//保存并解锁            }        }//..}



这里就会调用View的draw,将数据画到canvas上。


我们回头看setView里的第二个方法:sWindowSession.add。

不知道大家看上面的时候有没有觉得奇怪,viewroot对应的windowstate是什么时候创建的?

就在add里。

IWindowSession的add方法就是Session的本地proxy方法,通过Binder机制后实际会调用到Session的add方法:

    public int add(IWindow window, int seq, WindowManager.LayoutParams attrs,            int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {        return mService.addWindow(this, window, seq, attrs, viewVisibility, outContentInsets,                outInputChannel);    }
直接调用WindowManagerService的addWindow方法:

    public int addWindow(Session session, IWindow client, int seq,            WindowManager.LayoutParams attrs, int viewVisibility,            Rect outContentInsets, InputChannel outInputChannel) {//...            win = new WindowState(this, session, client, token,//...            win.attach();            mWindowMap.put(client.asBinder(), win);}

其中和windowstate的创建相关的主要是这三句话,首先new了一个windowstate对象,其次调用它的attach方法,再其次将他放入全局的表中(和client一一对应)。

我们看下他的attach方法:


 

    void attach() {        if (WindowManagerService.localLOGV) Slog.v(            WindowManagerService.TAG, "Attaching " + this + " token=" + mToken            + ", list=" + mToken.windows);        mSession.windowAddedLocked();    }
mSession就是上文传入的session:

    void windowAddedLocked() {        if (mSurfaceSession == null) {            if (WindowManagerService.localLOGV) Slog.v(                WindowManagerService.TAG, "First window added to " + this + ", creating SurfaceSession");            mSurfaceSession = new SurfaceSession();//初始化surfacesession            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(                    WindowManagerService.TAG, "  NEW SURFACE SESSION " + mSurfaceSession);            mService.mSessions.add(this);//将session加入WMS的全局表中        }        mNumWindow++;    }

这里又看到了一个另外的对象--surfaceSession:

    public SurfaceSession() {        init();    }
init是native的方法,本尊是在android_view_surface.cpp中的
static void SurfaceSession_init(JNIEnv* env, jobject clazz){    sp<SurfaceComposerClient> client = new SurfaceComposerClient;    client->incStrong(clazz);    env->SetIntField(clazz, sso.client, (int)client.get());}

到这里我们就应该明白了上文中创建surfacecontrol的SurfaceComposerClient是哪里来的吧!



原创粉丝点击