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是哪里来的吧!
- Android Activity是怎么画出来的
- 怎么看地图?还是要一起看看地图是怎么画出来的!
- StarUML中时序图用户的人怎么画出来
- 画出来的理解
- Android View的LayoutParams是怎么来的
- 阳历是怎么来的
- 情人节是怎么来的
- bzImage是怎么来的
- 母亲节是怎么来的
- 性能是怎么来的
- 源码解析:dialog, popupwindow, 和activity 的第一个view是怎么来的?
- 鼠标画出来的汽车
- GDI+ 双缓冲 画出来的透明图片是黑色的
- 微软的收入是怎么来的
- -128的补码是怎么来的
- PS用圆角矩形工具画出来的是实线而是虚线,哪里出问题了?
- 0x33f00038是怎么得出来的?
- 不知道积分是怎么来的
- 1001 小Q系列故事——电梯里的爱情
- android GSM+CDMA基站定位
- Notification简介
- 关于MFC 主菜单Alt无响应
- 汇编初时化内存空间为空的函数
- Android Activity是怎么画出来的
- 北大acm1008题
- 提高Media SDK效率之多线程篇
- hive 配置参数说明
- YearsBetween、MonthsBetween ... YearSpan、MonthSpan ... 间隔时间
- HDU3374(String Problem)字符串-最小表示法+KMP
- DictForGeeks,我自己写的自定义词库的词典,支持英-中,中-英,也可以当电话本用。
- 韩信走马分酒问题(回溯)
- UvaLive-4254-Processor