Window和view的关系

来源:互联网 发布:大数据的主要来源 编辑:程序博客网 时间:2024/05/16 15:56

一、WIndow和windowManager
Window是一个抽象类,它的具体实现是PhoneWindow,创建一个window很简单,只需要创建一个windowManager即可,window具体实现在windowManagerService中,windowManager和windowManagerService的交互是一个IPC的过程。
下面是用windowManager的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
mFloatingButton = new Button(this);
      mFloatingButton.setText( "window");
      mLayoutParams = new WindowManager.LayoutParams(
          LayoutParams. WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,
          PixelFormat. TRANSPARENT);
      mLayoutParams. flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
          | LayoutParams. FLAG_NOT_FOCUSABLE
          | LayoutParams. FLAG_SHOW_WHEN_LOCKED;
      mLayoutParams. type = LayoutParams. TYPE_SYSTEM_ERROR;
      mLayoutParams. gravity = Gravity. LEFT | Gravity. TOP;
      mLayoutParams. x = 100;
      mLayoutParams. y = 300;
      mFloatingButton.setOnTouchListener( this);
      mWindowManager.addView( mFloatingButton, mLayoutParams); 

flags和type两个属性很重要,下面对一些属性进行介绍,首先是flags:
FLAG_NOT_TOUCH_MODAL表示不需要获取焦点,也不需要接收各种输入,最终事件直接传递给下层具有焦点的window。
FLAG_NOT_FOCUSABLE:在此window外的区域单击事件传递到底层window中。当前的区域则自己处理,这个一般都要设置,很重要。
FLAG_SHOW_WHEN_LOCKED :开启可以让window显示在锁屏界面上。
再来看下type这个参数:
window有三种类型:应用window,子window,系统window。应用类对应一个Activity,子Window不能单独存在,需要附属在父Window上,比如常用的Dialog。系统Window是需要声明权限再创建的window,如toast等。
window有z-ordered属性,层级越大,越在顶层。应用window层级1-99,子window1000-1999,系统2000-2999。这此层级对应着windowManager的type参数。系统层级常用的有两个TYPE_SYSTEM_OVERLAY或者TYPE_SYSTEM_ERROR。比如想用TYPE_SYSTEM_ERROR,只需
mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR。还要添加权限<uses-permission andorid:name="android.permission.SYSTEM_ALERT_WINDOW"/>。
有了对window的基本认识之后,我们来看下它底层如何实现加载View的。
二、window的创建
其实Window的创建跟之前我写的一篇博客LayoutInflater源码分析有点相似。Window的创建是在Activity创建的attach方法中,通过PolicyManager的makeNewWindow方法。Activity中实现了Window的Callback接口,因此当window状态改变时就会回调Activity方法。如onAttachedToWindow等。PolicyManager的真正实现类是Policy,看下它的代码:

?
1
2
3
publicWindow makeNewWindow(Context context) {
    returnnew PhoneWindow(context);
  }

到此Window创建完成。
下面分析view是如何附属到window上的。看Activity的setContentView方法。

?
1
2
3
4
publicvoid setContentView(intlayoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
  }

两部分,设置内容和设置ActionBar。window的具体实现是PhoneWindow,看它的setContent。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
publicvoid setContentView(intlayoutResID) {
    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
    // decor, when theme attributes and the like are crystalized. Do not check the feature
    // before this happens.
    if(mContentParent == null) {
      installDecor();
    }elseif (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
      mContentParent.removeAllViews();
    }
  
    if(hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
      finalScene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
          getContext());
      transitionTo(newScene);
    }else{
      mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    finalCallback cb = getCallback();
    if(cb != null&& !isDestroyed()) {
      cb.onContentChanged();
    }
  

看到了吧,又是分析它。
这里分三步执行:
1.如果没有DecorView,在installDecor中的generateDecor()创建DecorView。之前就分析过,这次就不再分析它了。
2.将View添加到decorview中的mContentParent中。
3.回调Activity的onContentChanged接口。
经过以上操作,DecorView创建了,但还没有正式添加到Window中。在ActivityResumeActivity中首先会调用Activity的onResume,再调用Activity的makeVisible,makeVisible中真正添加view ,代码如下:

?
1
2
3
4
5
6
7
8
voidmakeVisible() {
   if(!mWindowAdded) {
     ViewManager wm = getWindowManager();
     wm.addView(mDecor, getWindow().getAttributes());
     mWindowAdded = true;
   }
   mDecor.setVisibility(View.VISIBLE);
 }

通过上面的addView方法将View添加到Window。
三、Window操作View内部机制
1.window的添加

一个window对应一个view和一个viewRootImpl,window和view通过ViewRootImpl来建立联系,它并不存在,实体是view。只能通过 windowManager来操作它。
windowManager的实现类是windowManagerImpl。它并没有直接实现三大操作,而是委托给WindowManagerGlobal。addView的实现分为以下几步:
1).检查参数是否合法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if(view == null) {
      thrownew IllegalArgumentException("view must not be null");
    }
    if(display == null) {
      thrownew IllegalArgumentException("display must not be null");
    }
    if(!(params instanceofWindowManager.LayoutParams)) {
      thrownew IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }
  
    finalWindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
    if(parentWindow != null) {
      parentWindow.adjustLayoutParamsForSubWindow(wparams);
    }else{
      // If there's no parent and we're running on L or above (or in the
      // system context), assume we want hardware acceleration.
      finalContext context = view.getContext();
      if(context != null
          && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
        wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
      }
    }

2).创建ViewRootImpl并将View添加到列表中。

?
1
2
3
4
5
6
7
root = newViewRootImpl(view.getContext(), display);
  
      view.setLayoutParams(wparams);
  
      mViews.add(view);
      mRoots.add(root);
      mParams.add(wparams);

3).通过ViewRootImpl来更新界面并完成window的添加过程 。
root.setView(view, wparams, panelParentView);  
上面的root就是ViewRootImpl,setView中通过requestLayout()来完成异步刷新,看下requestLayout:

?
1
2
3
4
5
6
7
publicvoid requestLayout() {
    if(!mHandlingLayoutInLayoutRequest) {
      checkThread();
      mLayoutRequested = true;
      scheduleTraversals();
    }
  }

接下来通过WindowSession来完成window添加过程,WindowSession是一个Binder对象,真正的实现类是 Session,window的添加是一次IPC调用。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try{
          mOrigWindowType = mWindowAttributes.type;
          mAttachInfo.mRecomputeGlobalAttributes = true;
          collectViewAttributes();
          res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
              getHostVisibility(), mDisplay.getDisplayId(),
              mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
        }catch(RemoteException e) {
          mAdded = false;
          mView = null;
          mAttachInfo.mRootView = null;
          mInputChannel = null;
          mFallbackEventHandler.setView(null);
          unscheduleTraversals();
          setAccessibilityFocus(null,null);
          thrownew RuntimeException("Adding window failed", e);
}

 在Session内部会通过WindowManagerService来实现Window的添加。

?
1
2
3
4
5
6
publicint addToDisplay(IWindow window, intseq, WindowManager.LayoutParams attrs,
     intviewVisibility, intdisplayId, Rect outContentInsets, Rect outStableInsets,
     InputChannel outInputChannel) {
   returnmService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
       outContentInsets, outStableInsets, outInputChannel);
 }

在WindowManagerService内部会为每一个应用保留一个单独的session。
2.window的删除
看下WindowManagerGlobal的removeView:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
publicvoid removeView(View view, booleanimmediate) {
    if(view == null) {
      thrownew IllegalArgumentException("view must not be null");
    }
  
    synchronized(mLock) {
      intindex = findViewLocked(view, true);
      View curView = mRoots.get(index).getView();
      removeViewLocked(index, immediate);
      if(curView == view) {
        return;
      }
  
      thrownew IllegalStateException("Calling with view " + view
          +" but the ViewAncestor is attached to " + curView);
    }
  }

首先调用findViewLocked来查找删除view的索引,这个过程就是建立数组遍历。然后再调用removeViewLocked来做进一步的删除。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
privatevoid removeViewLocked(intindex, booleanimmediate) {
    ViewRootImpl root = mRoots.get(index);
    View view = root.getView();
  
    if(view != null) {
      InputMethodManager imm = InputMethodManager.getInstance();
      if(imm != null) {
        imm.windowDismissed(mViews.get(index).getWindowToken());
      }
    }
    booleandeferred = root.die(immediate);
    if(view != null) {
      view.assignParent(null);
      if(deferred) {
        mDyingViews.add(view);
      }
    }
  }

真正删除操作是viewRootImpl来完成的。windowManager提供了两种删除接口,removeViewImmediate,removeView。它们分别表示异步删除和同步删除。具体的删除操作由ViewRootImpl的die来完成。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
booleandie(booleanimmediate) {
    // Make sure we do execute immediately if we are in the middle of a traversal or the damage
    // done by dispatchDetachedFromWindow will cause havoc on return.
    if(immediate && !mIsInTraversal) {
      doDie();
      returnfalse;
    }
  
    if(!mIsDrawing) {
      destroyHardwareRenderer();
    }else{
      Log.e(TAG,"Attempting to destroy the window while drawing!\n" +
          " window=" + this+ ", title=" + mWindowAttributes.getTitle());
    }
    mHandler.sendEmptyMessage(MSG_DIE);
    returntrue;
  }

由上可知如果是removeViewImmediate,立即调用doDie,如果是removeView,用handler发送消息,ViewRootImpl中的Handler会处理消息并调用doDie。重点看下doDie:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
voiddoDie() {
    checkThread();
    if(LOCAL_LOGV) Log.v(TAG, "DIE in " + this+ " of " + mSurface);
    synchronized(this) {
      if(mRemoved) {
        return;
      }
      mRemoved = true;
      if(mAdded) {
        dispatchDetachedFromWindow();
      }
  
      if(mAdded && !mFirst) {
        destroyHardwareRenderer();
  
        if(mView != null) {
          intviewVisibility = mView.getVisibility();
          booleanviewVisibilityChanged = mViewVisibility != viewVisibility;
          if(mWindowAttributesChanged || viewVisibilityChanged) {
            // If layout params have been changed, first give them
            // to the window manager to make sure it has the correct
            // animation info.
            try{
              if((relayoutWindow(mWindowAttributes, viewVisibility, false)
                  & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                mWindowSession.finishDrawing(mWindow);
              }
            }catch(RemoteException e) {
            }
          }
  
          mSurface.release();
        }
      }
  
      mAdded = false;
    }
    WindowManagerGlobal.getInstance().doRemoveView(this);
  }

主要做四件事:
1.垃圾回收相关工作,比如清数据,回调等。
2.通过Session的remove方法删除Window,最终调用WindowManagerService的removeWindow

3.调用dispathDetachedFromWindow,在内部会调用onDetachedFromWindow()和onDetachedFromWindowInternal()。当view移除时会调用onDetachedFromWindow,它用于作一些资源回收。
4.通过doRemoveView刷新数据,删除相关数据,如在mRoot,mDyingViews中删除对象等。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
voiddoRemoveView(ViewRootImpl root) {
    synchronized(mLock) {
      finalint index = mRoots.indexOf(root);
      if(index >= 0) {
        mRoots.remove(index);
        mParams.remove(index);
        finalView view = mViews.remove(index);
        mDyingViews.remove(view);
      }
    }
    if(HardwareRenderer.sTrimForeground && HardwareRenderer.isAvailable()) {
      doTrimForeground();
    }
  }

3.更新window
看下WindowManagerGlobal中的updateViewLayout。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
publicvoid updateViewLayout(View view, ViewGroup.LayoutParams params) {
    if(view == null) {
      thrownew IllegalArgumentException("view must not be null");
    }
    if(!(params instanceofWindowManager.LayoutParams)) {
      thrownew IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }
  
    finalWindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
  
    view.setLayoutParams(wparams);
  
    synchronized(mLock) {
      intindex = findViewLocked(view, true);
      ViewRootImpl root = mRoots.get(index);
      mParams.remove(index);
      mParams.add(index, wparams);
      root.setLayoutParams(wparams,false);
    }
  }

通过viewRootImpl的setLayoutParams更新viewRootImpl的layoutParams,接着scheduleTraversals对view重新布局,包括测量,布局,重绘,此外它还会通过WindowSession来更新window。这个过程由WindowManagerService实现。这跟上面类似,就不再重复,到此Window底层源码就分析完啦。






Android 中Activity,Window和View之间的关系

标签: androidnulljavamatrix活动object
 3582人阅读 评论(1) 收藏 举报
 分类:
 

本文是我从以下地址拷贝来的:  http://lpqsun-126-com.iteye.com/blog/1409989

保存下来,仔细阅读。


我想大多数人,对于这3个东西的概念能区分,但是具体区别在哪却很难说出来。

我这里根据我个人的理解来讲讲我个人对这3个概念的理解。当然这里设计到通用的事件窗口模型等通用GUI设计,我这里就不打算讲了,纯粹从概念上来进行区分。

Activity是Android应用程序的载体,允许用户在其上创建一个用户界面,并提供用户处理事件的API,如onKeyEvent, onTouchEvent等。 并维护应用程序的生命周期(由于android应用程序的运行环境和其他操作系统不同,android的应用程序是运行在框架之内,所以他的应用程序不能当当从进程的级别去考虑,而更多是从概念上去考虑。android应用程序是由多个活动堆积而成,而各个活动又有其独立的生命周期)。Activity本身是个庞大的载体,可以理解成是应用程序的载体,如果木有Activity,android应用将无法运行。也可以理解成android应用程序的入口。Acivity的实例对象由系统维护。系统服务ActivityManager负责维护Activity的实例对象,并根据运行状态维护其状态信息。

但在用户级别,程序员可能根愿意理解成为一个界面的载体。但仅仅是个载体,它本身并不负责任何绘制。Activity的内部实现,实际上是聚了一个Window对象。Window是一个抽象类,它的具体是在android_src_home/framework/policies/base/phone/com/android/internal/policy/impl目录下的PhoneWindow.java。

当我们调用Acitivity的 setContentView方法的时候实际上是调用的Window对象的setContentView方法,所以我们可以看出Activity中关于界面的绘制实际上全是交给Window对象来做的。绘制类图的话,可以看出Activity聚合了一个Window对象。

下面是PhoneWindow中的setContentView方法的实现:

Java代码  收藏代码
  1. @Override  
  2.   
  3.     public void setContentView(View view, ViewGroup.LayoutParams params) {  
  4.   
  5.         if (mContentParent == null) {  
  6.   
  7.             installDecor();  
  8.   
  9.         } else {  
  10.   
  11.             mContentParent.removeAllViews();  
  12.   
  13.         }  
  14.   
  15.         mContentParent.addView(view, params);  
  16.   
  17.         final Callback cb = getCallback();  
  18.   
  19.         if (cb != null) {  
  20.   
  21.             cb.onContentChanged();  
  22.   
  23.         }  
  24.   
  25.     }  

 Window内部首先判断mContentParent是否为空,然后调用installDecor方法(安装装饰器),我们看看这个方法如何实现的 

Java代码  收藏代码
  1. private void installDecor() {  
  2.   
  3.         if (mDecor == null) {  
  4.   
  5.             mDecor = generateDecor();  
  6.   
  7.             mDecor.setIsRootNamespace(true);  
  8.   
  9.         }  
  10.   
  11.         if (mContentParent == null) {  
  12.   
  13.             mContentParent = generateLayout(mDecor);  
  14.   
  15.             mTitleView = (TextView)findViewById(com.android.internal.R.id.title);  
  16.   
  17.             if (mTitleView != null) {  
  18.   
  19.                 if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {  
  20.   
  21.                     View titleContainer = findViewById(com.android.internal.R.id.title_container);  
  22.   
  23.                     if (titleContainer != null) {  
  24.   
  25.                         titleContainer.setVisibility(View.GONE);  
  26.   
  27.                     } else {  
  28.   
  29.                         mTitleView.setVisibility(View.GONE);  
  30.   
  31.                     }  
  32.   
  33.                     if (mContentParent instanceof FrameLayout) {  
  34.   
  35.                         ((FrameLayout)mContentParent).setForeground(null);  
  36.   
  37.                     }  
  38.   
  39.                 } else {  
  40.   
  41.                     mTitleView.setText(mTitle);  
  42.   
  43.                 }  
  44.   
  45.             }  
  46.   
  47.         }  
  48.   
  49.     }  
 

在该方法中,首先创建一个DecorView,DecorView是一个扩张FrameLayout的类,是所有窗口的根View。我们在Activity中调用的setConctentView就是放到DecorView中了。这是我们类图的聚合关系如下:

Activity--->Window--->DecorView

这是我们得出这3个类之间最直接的一个关系。

我们详细分析一下,类对象是如何被创建的。

先不考虑Activity的创建(因为 Acitivity的实例由ActivityManager维护,是在另一个进程设计到IPC的通信,后面会讲到),而考虑Window和View的创建。

Activity被创建后,系统会调用它的attach方法来将Activity添加到ActivityThread当中。我们找到Activity的attach方法如下:

Java代码  收藏代码
  1. final void attach(Context context, ActivityThread aThread,  
  2.   
  3.             Instrumentation instr, IBinder token, int ident,  
  4.   
  5.             Application application, Intent intent, ActivityInfo info,  
  6.   
  7.             CharSequence title, Activity parent, String id,  
  8.   
  9.             Object lastNonConfigurationInstance,  
  10.   
  11.             HashMap<String,Object> lastNonConfigurationChildInstances,  
  12.   
  13.             Configuration config) {  
  14.   
  15.         attachBaseContext(context);  
  16.   
  17.        mWindow= PolicyManager.makeNewWindow(this);  
  18.   
  19.         mWindow.setCallback(this);  
  20.   
  21.         if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {  
  22.   
  23.             mWindow.setSoftInputMode(info.softInputMode);  
  24.   
  25.         }  
  26.   
  27.         mUiThread = Thread.currentThread();  
  28.   
  29.         mMainThread = aThread;  
  30.   
  31.         mInstrumentation = instr;  
  32.   
  33.         mToken = token;  
  34.   
  35.         mIdent = ident;  
  36.   
  37.         mApplication = application;  
  38.   
  39.         mIntent = intent;  
  40.   
  41.         mComponent = intent.getComponent();  
  42.   
  43.         mActivityInfo = info;  
  44.   
  45.         mTitle = title;  
  46.   
  47.         mParent = parent;  
  48.   
  49.         mEmbeddedID = id;  
  50.   
  51.         mLastNonConfigurationInstance = lastNonConfigurationInstance;  
  52.   
  53.         mLastNonConfigurationChildInstances = lastNonConfigurationChildInstances;  
  54.   
  55.         mWindow.setWindowManager(null, mToken, mComponent.flattenToString());  
  56.   
  57.         if (mParent != null) {  
  58.   
  59.             mWindow.setContainer(mParent.getWindow());  
  60.   
  61.         }  
  62.   
  63.         mWindowManager = mWindow.getWindowManager();  
  64.   
  65.         mCurrentConfig = config;  
  66.   
  67.     }  
 

我们看红色的代码部分,就是创建Window对象的代码。感兴趣的同学可以跟踪去看看具体是如何创建的。其实很简单,其内部实现调用了Policy对象的makeNewWindow方法,其方法直接new了一个PhoneWindow对象如下:

public PhoneWindow makeNewWindow(Context context) {

        returnnew PhoneWindow(context);

 }

这时我们已经可以把流程串起来,Activity创建后系统会调用其attach方法,将其添加到ActivityThread当中,在attach方法中创建了一个window对象。

下面分析View的创建。我们知道Window聚合了DocerView,当用户调用setContentView的时候会把一颗View树仍给DocerView.View树是已经创建好的实例对象了,所以我们研究的是DocerView是个什么东西,它是如何被创建的。

我们回头看看Window实现里边的setContentView方法,我们看上面代码的红色部分setContentView-> installDecor-> generateDecor.

 

generateDecor直接new了一个DecorView对象:  

protected DecorView generateDecor() {

        returnnew DecorView(getContext(), -1);

 }

我们可以去看看DecorView的实现,它是PhoneWindow的一个内部类。实现很简单,它默认会包含一个灰色的标题栏,然后在标题栏下边会包含一个空白区域用来当用户调用setContentView的时候放置用户View,并传递事件,这里不做详细分析,感兴趣同学可以自己研究研究。

当DecorView创建好之后再回到Window中的setContentView方法中来,见上面代码蓝色部分,调用

  mContentParent.addView(view, params);

来将用户的View树添加到DecorView中。

到这时为止,我想我们已经很清晰的认识到它们3者之间的关系,并知道其创建流程。

现在总结一下:

Activity在onCreate之前调用attach方法,在attach方法中会创建window对象。window对象创建时并木有创建Decor对象对象。用户在Activity中调用setContentView,然后调用window的setContentView,这时会检查DecorView是否存在,如果不存在则创建DecorView对象,然后把用户自己的View 添加到DecorView中。

上篇讲解了3个对象之间的关系和创建的时机。这篇讲解窗口是如何被绘制出来的。

首先,我们看一个概念。就是View的draw方法的doc:

Manually render this view (and all of its children) to the given Canvas.

意思是说把View绘制在画布上。个人觉得这个概念很重要,View和Canvas 的关系,按常规的思维,肯定认为View聚合了Canvas对象,然后在View的onDraw 方法中,在View中绘制图形。实际上恰恰相反,Canvas 是由系统提供,view通过draw方法来把自身绘制在画布上。如果这样来理解的话,很多东西理解起来就很自然了。系统在window中提供一个Canvas对象,DocerView通过调用draw方法来将自己绘制到canvas上。draw方法实际上是一个递归方法,他会循环调用孩子View的draw方法来完成整棵树的绘制。所以实际上一个界面的绘制所用的Cavans是同一个对象。Canvas内部聚合了Matrix对象来实现坐标系的变换。

这里将的是题外话,只是想让大家理解一个东西。

下面回到系统如何来绘制一个窗口。

android 系统提供了WindowManager,WindowManager顾名思义窗口管理器。实际上它只是对WindowManager服务做了一个包装。其内部实现通过ISessionWindow和IWindow接口来和WindowManager服务来通信,这里设计到IPC的概念。IPC即进程间的通讯,ANDROID通过IBinder接口来实现,IBinder通过transact方法来实现进程间的交互,这是一个使用很不友好的接口,好在android还提供了aidl的更人性化的接口,它使得IPC通信就像调用普通的JAVA方法那样便捷。不了解aidl的同学可以自行研究研究(其实我自己也是半桶水,了解概念,而用的不熟悉)

我来看Window是如何被添加到WindowManager的.

Activity有一个public的方法setVisible用来控制Activity的窗口是否显示。

我们看其内部实现发现其调用了makeVisible方法,该方法就是让Window显示在屏幕当中的方法,实现如下:

Java代码  收藏代码
  1. void makeVisible() {  
  2.   
  3.        if (!mWindowAdded) {  
  4.   
  5.            ViewManager wm = getWindowManager();  
  6.   
  7.            wm.addView(mDecor, getWindow().getAttributes());  
  8.   
  9.            mWindowAdded = true;  
  10.   
  11.        }  
  12.   
  13.        mDecor.setVisibility(View.VISIBLE);  
  14.   
  15.    }  
 

这时我们立马就明白了,Activity通过Context来获取WindowManager对象,然后把Window对象的DocerView添加到了WindowManager 服务中,所以android的窗口的创建和显示并不是在同一个进程中,而是把窗口的绘制和管理交给了专门的WindowManager服务,这也是android framework给我提供的基础服务。

在上面绿色的代码当中,我们看看mDeocr是在哪被创建的。

Java代码  收藏代码
  1. public void onWindowAttributesChanged(WindowManager.LayoutParams params) {  
  2.   
  3.       // Update window manager if: we have a view, that view is  
  4.   
  5.        // attached to its parent (which will be a RootView), and  
  6.   
  7.        // this activity is not embedded.  
  8.   
  9.         if (mParent == null) {  
  10.   
  11.             View decor = mDecor;  
  12.   
  13.             if (decor != null && decor.getParent() != null) {  
  14.   
  15.                 getWindowManager().updateViewLayout(decor, params);  
  16.   
  17.             }  
  18.   
  19.         }  
  20.   
  21.     }  
 

搜索代码发现其创建的地方如上面红色代码。

这时我们已经知道,Activity创建好Window之后只要调用WindowManager 的addView方法来将Window的DocerView添加进去即可是使Window显示出来。还方法Window其实是Activity中的概念,在WindowManager中是直接和View打交道的。

下面我们开始研究WindowManager对象,打开其源代码,发现它是一个接口,且只是简单的扩展了ViewManager接口.并增加了一个方法

getDefaultDisplay():Display.  内部还有一个继承自ViewGroup.LayoutParam的内部类。

我们在framework/base/core/java/android/view/WindowManagerImpl.java 中找到其实现类。

我们找到其核心的实现方法addView 方法,如下:

Java代码  收藏代码
  1. private void addView(View view, ViewGroup.LayoutParams params, boolean nest)  
  2.   
  3.     {  
  4.   
  5.         if (Config.LOGV) Log.v("WindowManager""addView view=" + view);  
  6.   
  7.         if (!(params instanceof WindowManager.LayoutParams)) {  
  8.   
  9.             throw new IllegalArgumentException(  
  10.   
  11.                     "Params must be WindowManager.LayoutParams");  
  12.   
  13.         }  
  14.   
  15.         final WindowManager.LayoutParams wparams  
  16.   
  17.                 = (WindowManager.LayoutParams)params;  
  18.   
  19.           
  20.   
  21.         ViewRoot root;  
  22.   
  23.         View panelParentView = null;  
  24.   
  25.           
  26.   
  27.         synchronized (this) {  
  28.   
  29.             // Here's an odd/questionable case: if someone tries to add a  
  30.   
  31.             // view multiple times, then we simply bump up a nesting count  
  32.   
  33.             // and they need to remove the view the corresponding number of  
  34.   
  35.             // times to have it actually removed from the window manager.  
  36.   
  37.             // This is useful specifically for the notification manager,  
  38.   
  39.             // which can continually add/remove the same view as a  
  40.   
  41.             // notification gets updated.  
  42.   
  43.             int index = findViewLocked(view, false);  
  44.   
  45.             if (index >= 0) {  
  46.   
  47.                 if (!nest) {  
  48.   
  49.                     throw new IllegalStateException("View " + view  
  50.   
  51.                             + " has already been added to the window manager.");  
  52.   
  53.                 }  
  54.   
  55.                 root = mRoots[index];  
  56.   
  57.                 root.mAddNesting++;  
  58.   
  59.                 // Update layout parameters.  
  60.   
  61.                 view.setLayoutParams(wparams);  
  62.   
  63.                 root.setLayoutParams(wparams, true);  
  64.   
  65.                 return;  
  66.   
  67.             }  
  68.   
  69.               
  70.   
  71.             // If this is a panel window, then find the window it is being  
  72.   
  73.             // attached to for future reference.  
  74.   
  75.             if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&  
  76.   
  77.                     wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {  
  78.   
  79.                 final int count = mViews != null ? mViews.length : 0;  
  80.   
  81.                 for (int i=0; i<count; i++) {  
  82.   
  83.                     if (mRoots[i].mWindow.asBinder() == wparams.token) {  
  84.   
  85.                         panelParentView = mViews[i];  
  86.   
  87.                     }  
  88.   
  89.                 }  
  90.   
  91.             }  
  92.   
  93.               
  94.   
  95.            root =newViewRoot(view.getContext());  
  96.   
  97.             root.mAddNesting = 1;  
  98.   
  99.             view.setLayoutParams(wparams);  
  100.   
  101.               
  102.   
  103.             if (mViews == null) {  
  104.   
  105.                 index = 1;  
  106.   
  107.                 mViews = new View[1];  
  108.   
  109.                 mRoots = new ViewRoot[1];  
  110.   
  111.                 mParams = new WindowManager.LayoutParams[1];  
  112.   
  113.             } else {  
  114.   
  115.                 index = mViews.length + 1;  
  116.   
  117.                 Object[] old = mViews;  
  118.   
  119.                 mViews = new View[index];  
  120.   
  121.                 System.arraycopy(old, 0, mViews, 0, index-1);  
  122.   
  123.                 old = mRoots;  
  124.   
  125.                 mRoots = new ViewRoot[index];  
  126.   
  127.                 System.arraycopy(old, 0, mRoots, 0, index-1);  
  128.   
  129.                 old = mParams;  
  130.   
  131.                 mParams = new WindowManager.LayoutParams[index];  
  132.   
  133.                 System.arraycopy(old, 0, mParams, 0, index-1);  
  134.   
  135.             }  
  136.   
  137.             index--;  
  138.   
  139.             mViews[index] = view;  
  140.   
  141.             mRoots[index] = root;  
  142.   
  143.             mParams[index] = wparams;  
  144.   
  145.         }  
  146.   
  147.         // do this last because it fires off messages to start doing things  
  148.   
  149.        root.setView(view, wparams, panelParentView);  
  150.   
  151.     }  
 

我们看看我标记未红色的两行代码  root =newViewRoot(view.getContext());和 root.setView(view, wparams, panelParentView);

创建了一个ViewRoot对象,然后把view添加到ViewRoot中。

ViewRoot对象是handler的一个实现,其聚合了ISessionWindow和IWindow对象来和WindowManager服务进行IPC通信。


0 0