Android addView过程

以前就知道有WindowManagerService这个东西,知道addView最终是跟WindowManagerService进行交互的,但是一直没有深入去看,去理解。

然后到网上搜搜资料。
看到老罗的文章后
http://blog.csdn.net/luoshengyang/article/details/8462738

我发现我更不懂了。还是试着自己看源码,自己尝试着去理解,虽然可能没有他理解的那么深刻,还有结构图,时序图,但是整个流程至少自己可以走通。

下面就贴上代码,把整个流程跑一遍。

注意:Android源码 2.3.1

这里我就从new Activity开始。

frameworks/base/core/java/android/app/ActivityThread

 private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
     ...
     ...
    activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
    ...
    activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstance,
                        r.lastNonConfigurationChildInstances, config);
    ...     
}

接收到AMS发来的消息后,开始创建Activity。

frameworks/base/core/java/android/app/Activity

 final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            Object lastNonConfigurationInstance,
            HashMap lastNonConfigurationChildInstances,
            Configuration config) {
        attachBaseContext(context);

        mWindow = PolicyManager.makeNewWindow(this);
        mWindow.setCallback(this);
  ...
        mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
  ...
    }

本文就不过多的介绍中间跳转的过程了,因为直接会有很方法重载,我就直接贴出关键的调用代码,希望大家能自己跟一遍,对理解,记忆都非常有好处。

这里最重要的3行代码

  1. PolicyManager.makeNewWindow创建了PhoneWindow
  2. 给PhoneWindow设置callback,也就是Activity本身。
  3. setWindowManager

frameworks/base/core/java/android/view/Window

 public void setWindowManager(WindowManager wm,
            IBinder appToken, String appName) {
        mAppToken = appToken;
        mAppName = appName;
        if (wm == null) {
            wm = WindowManagerImpl.getDefault();
        }
        mWindowManager = new LocalWindowManager(wm);
    }
}
public WindowManager getWindowManager() {
        return mWindowManager;
 }

虽然getWindowManager得到的是LocalWindowManager,但是其实
LocalWindowManager可以算个代理类,里面很多方法的具体实现还是在WindowManagerImpl。

其实我们当前分析的addView,以及与WMS交互流程会比前面AMS交互要难,因为AMS交互大部分的过程都是连续的,可以一步走到底,可是我们现在分析的就很难一步走到底。当然这是我的个人感觉。

现在newActivity创建了一些变量,走不下去,我们就继续回过头看看。其实这个时候触发了Activity的onCreate方法了。

frameworks/base/core/java/android/app/ActivityThread

private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  ...
mInstrumentation.callActivityOnCreate(activity, r.state);
  ...
}

回调我们写的onCreate。而这时候我们一般会setContentView去设置布局。

frameworks/base/core/java/android/app/Activity

public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
    }
...
public Window getWindow() {
        return mWindow;
    }
...

getWindow其实获取到的就是刚才初始化Activity中的mWindow,也就是PhoneWindw.
frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow

 @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null) {
            cb.onContentChanged();
        }
    }

...

 private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor();
            ...
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
            ...
        }
    }

protected DecorView generateDecor() {
        return new DecorView(getContext(), -1);
    }
...
 protected ViewGroup generateLayout(DecorView decor) {
...
 View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
}
...

这里代码 稍微有点多,但是逻辑上很简单,基本上都能看得懂。首先是前面调用了Activity的setContentView,其实最终是调用了PhoneWindow的setContentView。

在PhoneWindow中会判断是否创建了DecorView。如果没有创建的话,就会new DecorView 然后再根据用户设置的主题还有属性,获取到对应的layout布局,然后inflater之后(这里姑且把inflater之后的布局叫做RootView)add到DecorView之中。RootView其实是一个LinearLayout,分为三大块,状态栏,标题栏,用户的内容栏(其实就是一个FrameLayout)。

最后其实是调用了mLayoutInflater.inflate(layoutResID, mContentParent);
把setContentView设置的layout,inflater之后add到用户的内容栏中。

到了这一步之后,发现又无路可走了,再往前看看,performLaunchActivity也已经执行完了。然后确实是不知道下一步到底怎么走了,然后我搜了搜,其实这个时候触发了handleResumeActivity
frameworks/base/core/java/android/app/ActivityThread

 final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
    ...
      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);
       }
    ...
}

这几句代码很关键,因为我们知道其实整个界面最底层的其实是PhoneWindow,然后是DecorView,然后是RootView,接下来才是我们自己的View.前面流程只讲了创建DecorView然后add RootView 然后add 我们自定义的layout。

而这几句代码才把DecorView add到PhoneWindow中。
上面的getWindowManager()其实是LocalWindowManager,不过
LocalWindowManager其实只能算是一个代理类,具体的实现在WindowManagerImpl中。
frameworks/base/core/java/android/View/WindowManagerImpl

 private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
    {
       ...
      ViewRoot root;
      ...
      root = new ViewRoot(view.getContext());
      ...
      root.setView(view, wparams, panelParentView);  
}

ViewRoot在添加View的过程中是很重要的一个角色,现在终于出现了,我当前android源码是2.3.1,后面的版本中,ViewRoot被替换成了ViewRootImpl,但是这并没有什么关系,我们能把 这里的源码看懂了,新版中虽然有改动,但是还是能很快的理解的。

frameworks/base/core/java/android/View/ViewRoot

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;
        }
    }

public ViewRoot(Context context) {
        super();
        ...
        getWindowSession(context.getMainLooper());
        ...
}

看到getWindowSession这个方法其实会感到非常的熟悉,因为在前面AMS中也出现过相同的代码,就是创建一个代理类与ActivityManagerService利用Binder机制进行交互。这里也是一样的。是与WindowManagerService建立连接。

虽然代码看过去挺像的,但又有点不太一样,这里会比ActivityManagerService那里会稍微复杂点。下面我来具体分析下。
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowManager


...
...
case TRANSACTION_openSession:
{
data.enforceInterface(DESCRIPTOR);
com.android.internal.view.IInputMethodClient _arg0;
_arg0 = com.android.internal.view.IInputMethodClient.Stub.asInterface(data.readStrongBinder());
com.android.internal.view.IInputContext _arg1;
_arg1 = com.android.internal.view.IInputContext.Stub.asInterface(data.readStrongBinder());
android.view.IWindowSession _result = this.openSession(_arg0, _arg1);
reply.writeNoException();
reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));
return true;
}

...
public android.view.IWindowSession openSession(com.android.internal.view.IInputMethodClient client, com.android.internal.view.IInputContext inputContext) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.view.IWindowSession _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((client!=null))?(client.asBinder()):(null)));
_data.writeStrongBinder((((inputContext!=null))?(inputContext.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_openSession, _data, _reply, 0);
_reply.readException();
_result = android.view.IWindowSession.Stub.asInterface(_reply.readStrongBinder());
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
...

使用Binder机制与WindowManagerService交互,调用WindowManagerService的openSession方法

frameworks/base/services/java/com/android/server/WindowManagerService

...
 public IWindowSession openSession(IInputMethodClient client,
            IInputContext inputContext) {
        if (client == null) throw new IllegalArgumentException("null client");
        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
        Session session = new Session(client, inputContext);
        return session;
    }
...
private final class Session extends IWindowSession.Stub
            implements IBinder.DeathRecipient {
...
}

这个过程虽然有点复杂,但是还算连续,有了前面阅读过AMS源码经验,这里其实也是可以接受的。

最终的结果就是,调用WindowManagerService的openSession创建一个Session对象,这个Session对象其实也是IWindowSession.Stub的子类。然后把session这个对象重新write回来。然后调用

  _result = android.view.IWindowSession.Stub.asInterface(_reply.readStrongBinder());

在App进程中,读取到这个Session后,使用Binder机制,在本地创建IWindowSession.Stub.Proxy对象与WindowManagerService那边的Session对象建立连接。

虽然只是一句简单的代码

sWindowSession = IWindowManager.Stub.asInterface(
                            ServiceManager.getService("window"))
                            .openSession(imm.getClient(), imm.getInputContext());

但是里面涉及到了好多。
最终返回的sWindowSession,其实是一个IWindowSession.Stub.Proxy对象,用来与WindowManagerService的Session建立连接。

其实ViewRoot初始化的时候还有一个重要的变量。

 public ViewRoot(Context context) {
...
 mWindow = new W(this, context);
...
}

在前面介绍AMS的时候,我们都知道,App进程使用ActivityManagerProxy与ActivityManagerService进行交互,而ActivityManagerService则是使用ApplicationThreadProxy与App进程中的ApplicationThread进行交互。

大同小异,WindowManagerService想与App端进行交互,那么也需要一个类似ApplicationThread这样的Binder来接收WindowManagerService传递过来的信息。它就是W这个类。

那么我们继续往下看。

还是回到刚才的WindowManagerImpl,创建好了ViewRoot之后。
frameworks/base/core/java/android/view/WindowManagerImpl

 private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
    {
      private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
    {
       ...
      ViewRoot root;
      ...
      root = new ViewRoot(view.getContext());
      ...
      root.setView(view, wparams, panelParentView);  
}

继续是调用ViewRoot的setView

public void setView(View view, WindowManager.LayoutParams attrs,
            View panelParentView) {
      ...
      ...
    res = sWindowSession.add(mWindow, mWindowAttributes,
                            getHostVisibility(), mAttachInfo.mContentInsets,
                            mInputChannel);
    ...
}

调用刚才获取到的Session代理的add方法
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowSession


...
...
case TRANSACTION_add:
{
data.enforceInterface(DESCRIPTOR);
android.view.IWindow _arg0;
_arg0 = android.view.IWindow.Stub.asInterface(data.readStrongBinder());
android.view.WindowManager.LayoutParams _arg1;
if ((0!=data.readInt())) {
_arg1 = android.view.WindowManager.LayoutParams.CREATOR.createFromParcel(data);
}
else {
_arg1 = null;
}
int _arg2;
_arg2 = data.readInt();
android.graphics.Rect _arg3;
_arg3 = new android.graphics.Rect();
android.view.InputChannel _arg4;
_arg4 = new android.view.InputChannel();
int _result = this.add(_arg0, _arg1, _arg2, _arg3, _arg4);
reply.writeNoException();
reply.writeInt(_result);
if ((_arg3!=null)) {
reply.writeInt(1);
_arg3.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
if ((_arg4!=null)) {
reply.writeInt(1);
_arg4.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
...
public int add(android.view.IWindow window, android.view.WindowManager.LayoutParams attrs, int viewVisibility, android.graphics.Rect outContentInsets, android.view.InputChannel outInputChannel) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((window!=null))?(window.asBinder()):(null)));
if ((attrs!=null)) {
_data.writeInt(1);
attrs.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
_data.writeInt(viewVisibility);
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
if ((0!=_reply.readInt())) {
outContentInsets.readFromParcel(_reply);
}
if ((0!=_reply.readInt())) {
outInputChannel.readFromParcel(_reply);
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
...

还是使用Binder机制,调用了WindowManagerService下的Session对象的add方法。

其中值得关注的是,这里把我刚才提到的mWindow也就是W对象write给了WindowManagerService的Session,其实跟AMS的交互是一样的。Session那边可以利用W对象与App进程进行交互。

...
 public int addWindow(Session session, IWindow client,
            WindowManager.LayoutParams attrs, int viewVisibility,
            Rect outContentInsets, InputChannel outInputChannel) {
    
}
...
 private final class Session extends IWindowSession.Stub
            implements IBinder.DeathRecipient {
...
...
 public int add(IWindow window, WindowManager.LayoutParams attrs,
                int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {
            return addWindow(this, window, attrs, viewVisibility, outContentInsets,
                    outInputChannel);
        }
...
}

Session其实是WindowManagerService的一个内部类,最后还是调用了WindowManagerService的add方法。

我发现到了这里之后我又走不下去了,又往前找。
frameworks/base/core/java/android/app/ActivityThread

 final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
  ...
   ViewManager wm = a.getWindowManager();
                        View decor = r.window.getDecorView();
                        wm.updateViewLayout(decor, l);
  ...
}

addView之后,调用WindowManagerImpl的updateViewLayout。
frameworks/base/core/java/android/view/WindowManagerImpl

...
 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams
                = (WindowManager.LayoutParams)params;
        
        view.setLayoutParams(wparams);

        synchronized (this) {
            int index = findViewLocked(view, true);
            ViewRoot root = mRoots[index];
            mParams[index] = wparams;
            root.setLayoutParams(wparams, false);
        }
    }
...

最后一行调用ViewRoot setLayoutParams
frameworks/base/core/java/android/view/ViewRoot

...
case DO_TRAVERSAL:
         ...

            performTraversals();

          ...
            break;
...
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
            ...
            scheduleTraversals();
        }
    }
...
  public void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            sendEmptyMessage(DO_TRAVERSAL);
        }
    }
...

终于最后调用了,performTraversals。由于这个方法很重要,所以这里单独提取出来。

private void performTraversals() {
    final View host = mView;
    ...
    ...
   host.measure(childWidthMeasureSpec, childHeightMeasureSpec);

  ...
   host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
  ...
  ...
  draw(fullRedrawNeeded);
  ...
}

mView 其实就是刚才我们调用ViewRoote setView设置进来的DecorView。

多的我也就不说了,最熟悉的3个方法出现了。接下来其实就是遍历测量,遍历布局,遍历绘制。

总的来说,这里整个添加View的过程比前面的AMS管理生命周期代码跟踪起来要难。

这里我再简单的说下,界面显示后的,动态代码addView的过程。
frameworks/base/core/java/android/view/ViewGroup

 public void addView(View child, int index, LayoutParams params) {
        if (DBG) {
            System.out.println(this + " addView");
        }

        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
        // therefore, we call requestLayout() on ourselves before, so that the child's request
        // will be blocked at our level
        requestLayout();
        invalidate();
        addViewInner(child, index, params, false);
    }

requestLayout其实是View里的方法
frameworks/base/core/java/android/view/View

 public void requestLayout() {
        if (ViewDebug.TRACE_HIERARCHY) {
            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
        }

        mPrivateFlags |= FORCE_LAYOUT;

        if (mParent != null && !mParent.isLayoutRequested()) {
            mParent.requestLayout();
        }
    }

最后其实是调用mParent的方法,mParent其实是当前View的父控件,所以一步步往上调用,最后的话是调用DecorView的parent。

这就尴尬了,DecorView的 parent是谁呢?

前面其实已经介绍到了,我们最终是调用了WindowManagerImpl的addView,然后调用了ViewRoot的setView,让我们再来看一下setView.
frameworks/base/core/java/android/view/ViewRoot

public void setView(View view, WindowManager.LayoutParams attrs,
            View panelParentView) {
    ...
    view.assignParent(this);
    ...
}

这里其实就看出来了,ViewRoot直接把自己设置为了DecorView的parent。

所以requestLayout其实还是调用了ViewRoot的requestLayout.

public void requestLayout() {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }

最后还是调用了scheduleTraversals,然后还是跟前面的流程一样了。

好,过程很复杂,当时跟踪一遍了之后,还是收获很多的。

你可能感兴趣的:(Android addView过程)