小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

深入淺出 詳解Android Surface系統(tǒng)(2)

 leon0821 2013-08-15

JNI層

上面兩個類的JNI實(shí)現(xiàn)都在framework/base/core/jni/android_view_Surface.cpp中。

[---->SurfaceSession:: SurfaceSession()]

  1. public class SurfaceSession {  
  2.  
  3. /** Create a new connection with the surface flinger. */ 
  4.  
  5. public SurfaceSession() {  
  6.  
  7. init();  
  8.  

它的init函數(shù)對應(yīng)為:

[--->SurfaceSession_init]

  1. static void SurfaceSession_init(JNIEnv* env, jobject clazz)  
  2.  
  3. {  
  4.  
  5. //SurfaceSession對應(yīng)為SurfaceComposerClient  
  6.  
  7. sp client = new SurfaceComposerClient;  
  8.  
  9. client->incStrong(clazz);  
  10.  
  11. //Google常用做法,在JAVA對象中保存C++對象的指針。  
  12.  
  13. env->SetIntField(clazz, sso.client, (int)client.get());  
  14.  

Surface的init對應(yīng)為:

[--->Surface_init]

  1. static void Surface_init(  
  2.  
  3. JNIEnv* env, jobject clazz,  
  4.  
  5. jobject session,  
  6.  
  7. jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)  
  8.  
  9. {  
  10.  
  11. SurfaceComposerClient* client =  
  12.  
  13. (SurfaceComposerClient*)env->GetIntField(session, sso.client);  
  14.  
  15. sp surface;  
  16.  
  17. if (jname == NULL) {  
  18.  
  19. //client是SurfaceComposerClient,返回的surface是一個SurfaceControl  
  20.  
  21. //真得很復(fù)雜!  
  22.  
  23. surface = client->createSurface(pid, dpy, w, h, format, flags);  
  24.  
  25. else {  
  26.  
  27. const jchar* str = env->GetStringCritical(jname, 0);  
  28.  
  29. const String8 name(str, env->GetStringLength(jname));  
  30.  
  31. env->ReleaseStringCritical(jname, str);  
  32.  
  33. surface = client->createSurface(pid, name, dpy, w, h, format, flags);  
  34.  
  35. }  
  36.  
  37. //把surfaceControl信息設(shè)置到Surface對象中  
  38.  
  39. setSurfaceControl(env, clazz, surface);  
  40.  

  1. static void setSurfaceControl(JNIEnv* env, jobject clazz,  
  2.  
  3. const sp& surface)  
  4.  
  5. {  
  6.  
  7. SurfaceControl* const p =  
  8.  
  9. (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);  
  10.  
  11. if (surface.get()) {  
  12.  
  13. surface->incStrong(clazz);  
  14.  
  15. }  
  16.  
  17. if (p) {  
  18.  
  19. p->decStrong(clazz);  
  20.  
  21. }  
  22.  
  23. env->SetIntField(clazz, so.surfaceControl, (int)surface.get());  
  24.  

[--->Surface_copyFrom]

  1. static void Surface_copyFrom(  
  2.  
  3. JNIEnv* env, jobject clazz, jobject other)  
  4.  
  5. {  
  6.  
  7. const sp& surface = getSurfaceControl(env, clazz);  
  8.  
  9. const sp& rhs = getSurfaceControl(env, other);  
  10.  
  11. if (!SurfaceControl::isSameSurface(surface, rhs)) {  
  12.  
  13. setSurfaceControl(env, clazz, rhs);  
  14.  
  15. //把本地那個surface的surfaceControl對象轉(zhuǎn)移到outSurface上  
  16.  
  17. }  
  18.  

這里僅僅是surfaceControl的轉(zhuǎn)移,但是并沒有看到Surface相關(guān)的信息。

那么Surface在哪里創(chuàng)建的呢?為了解釋這個問題,我使用了終極武器,aidl。

1 終極武器AIDL

aidl可以把XXX.aidl文件轉(zhuǎn)換成對應(yīng)的java文件。我們剛才調(diào)用的是WindowSession的

relayOut函數(shù)。如下:

  1. sWindowSession.relayout(  
  2.  
  3. mWindow, params,  
  4.  
  5. (int) (mView.mMeasuredWidth * appScale + 0.5f),  
  6.  
  7. (int) (mView.mMeasuredHeight * appScale + 0.5f),  
  8.  
  9. viewVisibility, insetsPending, mWinFrame,  
  10.  
  11. mPendingContentInsets, mPendingVisibleInsets,  
  12.  
  13. mPendingConfiguration, mSurface); 

它的aidl文件在framework/base/core/java/android/view/IWindowSession.aidl中

  1. interface IWindowSession {  
  2.  
  3. int add(IWindow window, in WindowManager.LayoutParams attrs,  
  4.  
  5. in int viewVisibility, out Rect outContentInsets);  
  6.  
  7. void remove(IWindow window);  
  8.  
  9. //注意喔,這個outSurface前面的是out,表示輸出參數(shù),這個類似于C++的引用。  
  10.  
  11. int relayout(IWindow window, in WindowManager.LayoutParams attrs,  
  12.  
  13. int requestedWidth, int requestedHeight, int viewVisibility,  
  14.  
  15. boolean insetsPending, out Rect outFrame, out Rect outContentInsets,  
  16.  
  17. out Rect outVisibleInsets, out Configuration outConfig,  
  18.  
  19. out Surface outSurface); 

剛才說了,JNI及其JAVA調(diào)用只是copyFrom了SurfaceControl對象到outSurface中,但是沒看到哪里創(chuàng)建Surface。這其中的奧秘就在aidl文件編譯后生成的java文件中。

你在命令行下可以輸入:

aidl -Id:\android-2.2-froyo-20100625-source\source\frameworks\base\core\java\ -Id:\android-2.2-froyo-20100625-source\source\frameworks\base\Graphics\java d:\android-2.2-froyo-20100625-source\source\frameworks\base\core\java\android\view\IWindowSession.aidl test.java

以生成test.java文件。-I參數(shù)指定include目錄,例如aidl有些參數(shù)是在別的java文件中指定的,那么這個-I就需要把這些目錄包含進(jìn)來。

先看看ViewRoot這個客戶端生成的代碼是什么。

  1. public int relayout(  
  2.  
  3. android.view.IWindow window,  
  4.  
  5. android.view.WindowManager.LayoutParams attrs,  
  6.  
  7. int requestedWidth, int requestedHeight,  
  8.  
  9. int viewVisibility, boolean insetsPending,  
  10.  
  11. android.graphics.Rect outFrame,  
  12.  
  13. android.graphics.Rect outContentInsets,  
  14.  
  15. android.graphics.Rect outVisibleInsets,  
  16.  
  17. android.content.res.Configuration outConfig,  
  18.  
  19. android.view.Surface outSurface) ---->outSurface是第11個參數(shù)  
  20.  
  21. throws android.os.RemoteException  
  22.  
  23. {  
  24.  
  25. android.os.Parcel _data = android.os.Parcel.obtain();  
  26.  
  27. android.os.Parcel _reply = android.os.Parcel.obtain();  
  28.  
  29. int _result;  
  30.  
  31. try {  
  32.  
  33. _data.writeInterfaceToken(DESCRIPTOR);  
  34.  
  35. _data.writeStrongBinder((((window!=null))?(window.asBinder()):(null)));  
  36.  
  37. if ((attrs!=null)) {  
  38.  
  39. _data.writeInt(1);  
  40.  
  41. attrs.writeToParcel(_data, 0);  
  42.  
  43. }  
  44.  
  45. else {  
  46.  
  47. _data.writeInt(0);  
  48.  
  49. }  
  50.  
  51. _data.writeInt(requestedWidth);  
  52.  
  53. _data.writeInt(requestedHeight);  
  54.  
  55. _data.writeInt(viewVisibility);  
  56.  
  57. _data.writeInt(((insetsPending)?(1):(0)));  
  58.  
  59. //奇怪,outSurface的信息沒有寫到_data中。那.....  
  60.  
  61. mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);  
  62.  
  63. _reply.readException();  
  64.  
  65. _result = _reply.readInt();  
  66.  
  67. if ((0!=_reply.readInt())) {  
  68.  
  69. outFrame.readFromParcel(_reply);  
  70.  
  71. }  
  72.  
  73. ....  
  74.  
  75. if ((0!=_reply.readInt())) {  
  76.  
  77. outSurface.readFromParcel(_reply); //從Parcel中讀取信息來填充outSurface  
  78.  
  79. }  
  80.  
  81. }  
  82.  
  83. finally {  
  84.  
  85. _reply.recycle();  
  86.  
  87. _data.recycle();  
  88.  
  89. }  
  90.  
  91. return _result;  
  92.  

真奇怪啊,Binder客戶端這頭竟然沒有把outSurface的信息發(fā)過去。我們趕緊看看服務(wù)端。

服務(wù)端這邊處理是在onTranscat函數(shù)中。

  1. @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException  
  2.  
  3. {  
  4.  
  5. switch (code)  
  6.  
  7. {  
  8.  
  9. case TRANSACTION_relayout:  
  10.  
  11. {  
  12.  
  13. data.enforceInterface(DESCRIPTOR);  
  14.  
  15. android.view.IWindow _arg0;  
  16.  
  17. android.view.Surface _arg10;  
  18.  
  19. //剛才說了,Surface信息并沒有傳過來,那么我們在relayOut中看到的outSurface是怎么  
  20.  
  21. //出來的呢?看下面這句,原來在服務(wù)端這邊竟然new了一個新的Surface!!!  
  22.  
  23. _arg10 = new android.view.Surface();  
  24.  
  25. int _result = this.relayout(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10);  
  26.  
  27. reply.writeNoException();  
  28.  
  29. reply.writeInt(_result);  
  30.  
  31. //_arg10是copyFrom了,那怎么傳到客戶端呢?  
  32.  
  33. if ((_arg10!=null)) {  
  34.  
  35. reply.writeInt(1);//調(diào)用Surface的writeToParcel,把信息加入reply  
  36.  
  37. _arg10.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);  
  38.  
  39. }  
  40.  
  41. return true;  
  42.  

太詭異了!竟然有這么多花花腸子。我相信如果沒有aidl的幫助,我無論如何也不會知道這其中的奧妙。

那好,我們的流程明白了。

◆客戶端雖然傳了一個surface,但其實(shí)沒傳遞給服務(wù)端

◆服務(wù)端調(diào)用writeToParcel,把信息寫到Parcel中,然后數(shù)據(jù)傳回客戶端

◆客戶端調(diào)用Surface的readFromParcel,獲得surface信息。

那就去看看writeToParcel吧。

[---->Surface_writeToParcel]

  1. static void Surface_writeToParcel(  
  2.  
  3. JNIEnv* env, jobject clazz, jobject argParcel, jint flags)  
  4.  
  5. {  
  6.  
  7. Parcel* parcel = (Parcel*)env->GetIntField(  
  8.  
  9. argParcel, no.native_parcel);  
  10.  
  11. const sp& control(getSurfaceControl(env, clazz));  
  12.  
  13. //還好,只是把數(shù)據(jù)序列化到Parcel中  
  14.  
  15. SurfaceControl::writeSurfaceToParcel(control, parcel);  
  16.  
  17. if (flags & PARCELABLE_WRITE_RETURN_VALUE) {  
  18.  
  19. setSurfaceControl(env, clazz, 0);  
  20.  
  21. }  
  22.  

那看看客戶端的Surface_readFromParcel吧。

[----->Surface_readFromParcel]

  1. static void Surface_readFromParcel(  
  2.  
  3. JNIEnv* env, jobject clazz, jobject argParcel)  
  4.  
  5. {  
  6.  
  7. Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);  
  8.  
  9. //客戶端這邊還沒有surface呢  
  10.  
  11. const sp& control(getSurface(env, clazz));  
  12.  
  13. //不過我們看到希望了,根據(jù)服務(wù)端那邊Parcel信息來構(gòu)造一個新的surface  
  14.  
  15. sp rhs = new Surface(*parcel);  
  16.  
  17. if (!Surface::isSameSurface(control, rhs)) {  
  18.  
  19. setSurface(env, clazz, rhs); //把這個新surface賦給客戶端。終于我們有了surface!  
  20.  
  21. }  
  22.  

到此,我們終于七拐八繞的得到了surface,這其中經(jīng)歷太多曲折了。下一節(jié),我們將精簡這其中復(fù)雜的操作,統(tǒng)一歸到Native層,以這樣為切入點(diǎn)來了解Surface的工作流程和原理。

好,反正你知道ViewRoot調(diào)用了relayout后,Surface就真正從WindowManagerService那得到了。繼續(xù)回到ViewRoot,其中還有一個重要地方是我們知道卻不了解的。

  1. private void performTraversals() {  
  2.  
  3. // cache mView since it is used so much below...  
  4.  
  5. final View host = mView;  
  6.  
  7. boolean initialized = false;  
  8.  
  9. boolean contentInsetsChanged = false;  
  10.  
  11. boolean visibleInsetsChanged;  
  12.  
  13. try {  
  14.  
  15. relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);  
  16.  
  17. // relayoutWindow完后,我們得到了一個無比寶貴的Surface  
  18.  
  19. //那我們畫界面的地方在哪里?就在這個函數(shù)中,離relayoutWindow不遠(yuǎn)處。  
  20.  
  21. ....  
  22.  
  23. boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();  
  24.  
  25. if (!cancelDraw && !newSurface) {  
  26.  
  27. mFullRedrawNeeded = false;  
  28.  
  29. draw(fullRedrawNeeded); //draw?draw什么呀?  
  30.  

[--->ViewRoot::draw()]

  1. private void draw(boolean fullRedrawNeeded) {  
  2.  
  3. Surface surface = mSurface; //嘿嘿,不擔(dān)心了,surface資源都齊全了  
  4.  
  5. if (surface == null || !surface.isValid()) {  
  6.  
  7. return;  
  8.  
  9. }  
  10.  
  11. if (mAttachInfo.mViewScrollChanged) {  
  12.  
  13. mAttachInfo.mViewScrollChanged = false;  
  14.  
  15. mAttachInfo.mTreeObserver.dispatchOnScrollChanged();  
  16.  
  17. }  
  18.  
  19. int yoff;  
  20.  
  21. final boolean scrolling = mScroller != null && mScroller.computeScrollOffset();  
  22.  
  23. if (scrolling) {  
  24.  
  25. yoff = mScroller.getCurrY();  
  26.  
  27. else {  
  28.  
  29. yoff = mScrollY;  
  30.  
  31. }  
  32.  
  33. if (mCurScrollY != yoff) {  
  34.  
  35. mCurScrollY = yoff;  
  36.  
  37. fullRedrawNeeded = true;  
  38.  
  39. }  
  40.  
  41. float appScale = mAttachInfo.mApplicationScale;  
  42.  
  43. boolean scalingRequired = mAttachInfo.mScalingRequired;  
  44.  
  45. Rect dirty = mDirty;  
  46.  
  47. if (mUseGL) { //我們不用OPENGL  
  48.  
  49. ...  
  50.  
  51. }  
  52.  
  53. Canvas canvas;  
  54.  
  55. try {  
  56.  
  57. int left = dirty.left;  
  58.  
  59. int top = dirty.top;  
  60.  
  61. int right = dirty.right;  
  62.  
  63. int bottom = dirty.bottom;  
  64.  
  65. //從Surface中鎖定一塊區(qū)域,這塊區(qū)域是我們認(rèn)為的需要重繪的區(qū)域  
  66.  
  67. canvas = surface.lockCanvas(dirty);  
  68.  
  69. // TODO: Do this in native  
  70.  
  71. canvas.setDensity(mDensity);  
  72.  
  73. }  
  74.  
  75. try {  
  76.  
  77. if (!dirty.isEmpty() || mIsAnimating) {  
  78.  
  79. long startTime = 0L;  
  80.  
  81. try {  
  82.  
  83. canvas.translate(0, -yoff);  
  84.  
  85. if (mTranslator != null) {  
  86.  
  87. mTranslator.translateCanvas(canvas);  
  88.  
  89. }  
  90.  
  91. canvas.setScreenDensity(scalingRequired  
  92.  
  93. ? DisplayMetrics.DENSITY_DEVICE : 0);  
  94.  
  95. //mView就是之前的decoreView,  
  96.  
  97. mView.draw(canvas);  
  98.  
  99. }  
  100.  
  101. finally {  
  102.  
  103. //我們的圖畫完了,告訴surface釋放這塊區(qū)域  
  104.  
  105. surface.unlockCanvasAndPost(canvas);  
  106.  
  107. }  
  108.  
  109. if (scrolling) {  
  110.  
  111. mFullRedrawNeeded = true;  
  112.  
  113. scheduleTraversals();  
  114.  
  115. }  
  116.  

看起來,這個surface的用法很簡單嘛:

l lockSurface,得到一個畫布Canvas

l 調(diào)用View的draw,讓他們在這個Canvas上盡情繪圖才。另外,這個View會調(diào)用所有它的子View來畫圖,最終會進(jìn)入到View的onDraw函數(shù)中,在這里我們可以做定制化的界面美化工作。當(dāng)然,如果你想定制化整個系統(tǒng)畫圖的話,完全可以把performTranvsal看懂,然后再修改。

l unlockCanvasAndPost,告訴Surface釋放這塊畫布

當(dāng)然,這幾個重要函數(shù)調(diào)用干了具體的活。這些重要函數(shù),我們最終會精簡到Native層的。

2 總結(jié)

到這里,你應(yīng)該知道了一個Activity中,調(diào)用setContentView后它如何從系統(tǒng)中獲取一塊Surface,以及它是如何使用這個Surface的了。不得不說,關(guān)于UI這塊,Android絕對是夠復(fù)雜的。難怪2.3把UI這塊代碼基本重寫一遍,希望能夠簡單精煉點(diǎn)。

【編輯推薦】

  1. Android開發(fā):自定義GridView/ListView數(shù)據(jù)源
  2. Android自定義標(biāo)題欄:顯示網(wǎng)頁加載進(jìn)度
  3. Android應(yīng)用開發(fā)教程:兩個運(yùn)行的Activity之間的通信
  4. Android學(xué)習(xí)筆記:Activity跳轉(zhuǎn)

【責(zé)任編輯:小野 TEL:(010)68476606】

內(nèi)容導(dǎo)航
 第 1 頁:Activity是如何顯示的  第 2 頁:JNI層

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多