Android-setContentView()

结构图

  • 一个Activity对应一个window,window是在activity.attach()函数里面被创建的。
  • activity.attach() 在AMS创建Activity的时候调用的。
  • 在Activity的onCreate()函数里面调用setContentView()最后调用的是window的setContentView()。
  • 调用window.setContentView()函数,里面初始化了 DecorView,以及内部的TitleView和mConentParent,mConentParent是DecorView的子View。
  • 我们添加进去的R.layout.activity_main.xml文件最后转化成View,添加到mConentParent里面。
  • 这里的mConentParent 就是上图去掉TitleView的ContentView。

XML是如何显示出来的

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 将创建好的xml文件 传入 系统就帮我们显示出来了
        setContentView(R.layout.activity_main);
    }
点击进入Activity的setContentView();
 public void setContentView(@LayoutRes int layoutResID) {
        // 调用了一window的方法
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

 public Window getWindow() {
        return mWindow;
    }
这个mWindow什么时候创建的呢? Activity#attach()
@UnsupportedAppUsage
    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,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
        attachBaseContext(context);

       ....

        // 在这里创建了 Window对象
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
       
       ....
        
        // 这个时候也创建了windowmanager
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
       ....
       
    }
  • ActivityThread.performLaunchActivity()调用 activity.attach()
下面看一下 PhoneWindow.setContentView()
    @Override
    public void setContentView(View view) {
        // 先判断mContentParent是否初始化
        if (mContentParent == null) {
            // 划重点 --> 初始化Decor  
            // 当前activity第一次调用setContentView()
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            // 如果Activity没有过渡动画,多次调用setContentView()回走到这里
            // 移除mContentParent所有内部view
            mContentParent.removeAllViews();
        }

        // 判断是否使用了Activity的过度动画
        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            // 设置动画场景
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,getContext());
            transitionTo(newScene);
        } else {
            // 将资源文件通过LayoutInflater对象封装为View树
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            // 这个方法在Activity是一个空实现
            // 说明在Activity的布局改动时(setContentView或者addContentView 方法执行完毕后会回调该函数)
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }
installDecor(); 干了啥
private void installDecor(){
    if(mDecor==null){
        // 如果mDecor为空则创建一个DecorView实例
        if (mDecor == null) {
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }

        if (mContentParent == null) {
            // 如果mContentParent为空则通过generateLayout创建一个
            mContentParent = generateLayout(mDecor);
            ...
        }    

    }
}
  • 创建了DecorView和mContentParent
generateDecor(-1);
 protected DecorView generateDecor(int featureId) {
        Context context;
        if (mUseDecorContext) {
            Context applicationContext = getContext().getApplicationContext();
            if (applicationContext == null) {
                context = getContext();
            } else {
                context = new DecorContext(applicationContext, getContext());
                if (mTheme != -1) {
                    context.setTheme(mTheme);
                }
            }
        } else {
            context = getContext();
        }
        // 返回一个实例
        return new DecorView(context, featureId, this, getAttributes());
    }
到这里我们setContentView(R.layout.activity_main); xml文件已经添加到DecorView了。

每个Activity都有一个与之关联的window,那如何管理window呢?

Activity的创建 ActivityThread
    @Override
    public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {
       
        ....

        final Activity a = performLaunchActivity(r, customIntent);

        ....

        return a;
    }
performLaunchActivity() 在这里创建了一个Activity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
      ....
       Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }
     ....
}
DecorView和WindowManager是如何关联起来的?
  • activityThread.handleLaunchActivity()
@Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
        
        ....
        // 这里会调用activity.onResume()函数 
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        ...
        final Activity a = r.activity;
        ...

        if (r.window == null && !a.mFinished && willBeVisible) {
            // 获取Window对象
            r.window = r.activity.getWindow();
            // 获去Window中的DecorView对象
            View decor = r.window.getDecorView();
            // 在这里被放开了 
            decor.setVisibility(View.INVISIBLE);
            // 获取WindowManager对象
            // 这个WindowManager就是在activity.attach()的时候一起创建的
            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) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // 看这里  将DecorView 添加到 wm 里面去了 
                    // TODO 这就是为什么 activity.onResume()之后才有界面
                    wm.addView(decor, l);
                } else {
                    a.onWindowAttributesChanged(l);
                }
            }
            ...
            if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
                r.activity.mVisibleFromServer = true;
                mNumVisibleActivities++;
                if (r.activity.mVisibleFromClient) {
                    // 设置decorview可见
                    r.activity.makeVisible();
                }
           }

        } 
    }

ActivityThread.handleLaunchActivity()--> 去创建Activity
ActivityThread.performLaunchActivity()--> 去创建Activity
Activity.attach()--> activity创建的时候调用
Activity.onCreate()--> 生命周期函数
ActivityThread.handleResumeActivity()--> 调用下面的函数
ActivityThread.performResumeActivity()--> 返回ActivityClientRecord
Activity.onResume()--> 生命周期函数
windowManager.addView()

到这里 Activity的创建 DecorView的创建 WindowManager的创建以及DecorView添加到WindowManager,这也是为什么在onCreate()里面是获取不到View的宽高的。
ViewManager
public interface ViewManager{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
WindowManager
public interface WindowManager extends ViewManager {
      ....
}
WindowManagerImpl

public final class WindowManagerImpl implements WindowManager {

...

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInatance();
private final Context mContext;
private final Window mParentWindow;


public WindowManagerImpl(Context context) {
    this(context, null);
}

private WindowManagerImpl(Context context, Window parentWindow) {
    mContext = context;
    mParentWindow = parentWindow;
}


public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    return new WindowManagerImpl(mContext, parentWindow);
}

public WindowManagerImpl createPresentationWindowManager(Context displayContext) {
    return new WindowManagerImpl(displayContext, mParentWindow);
}

// 往Window中添加View
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

// 更新布局 
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.updateViewLayout(view, params);
}

// 将删除View的消息发送到MessageQueue中,稍厚删除
@Override
public void removeView(View view) {
    mGlobal.removeView(view, false);
}
   
// 立即删除window中的View 
@Override
public void removeViewImmediate(View view) {
    mGlobal.removeView(view, true);
}

...

}
  • WindowManagerImpl并没有直接实现操作View的相关方法,而是全部交给WindowManangerGlobal。WindowManagerGlobal 是一个单例类----即一个进程中最多仅有一个。创建WindowManagerGlobal对象的方式如下
public static WindowManagerGlobal getInstance() {
        synchronized (WindowManagerGlobal.class) {
            if (sDefaultWindowManager == null) {
                sDefaultWindowManager = new WindowManagerGlobal();
            }
            return sDefaultWindowManager;
        }
    }

private WindowManagerGlobal() {
}

深入分析WindowManagerGlobal(分析内部的三个方法)

  • addView(View view,ViewGroup.LayoutParams params)
    该方法的主要作用是将decorView添加到viewRootImpl中,通过viewRootImpl 对其内部进行管理
public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        
        // 参数检查
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        // 判断是否有父Window,从而调整当前窗口的布局参数
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            // 有,调整title和token
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            // 无,应用开启了硬件加速,decorView就开启 
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            if (mSystemPropertyUpdater == null) {
                // 创建一个Runnable,用来遍历更新所有ViewRootImpl,更新系统参数
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                // 添加到执行队列
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }

            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            // If this is a panel window, then find the window it is being
            // attached to for future reference.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }

            // 创建一个ViewRootImpl对象并保存在root变量中
            root = new ViewRootImpl(view.getContext(), display);
            // 给需要添加的View设置params,也就是decorview
            view.setLayoutParams(wparams);
            // 将decorview、布局参数以及新建的ViewRootImpl保存在三个集合中
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);

            try {
                // 将decorview设置给ViewRootImpl
                // ViewRootImpl向WMS添加新的窗口、申请Surface以及decorView在Surface的重绘动作
                // 这才是真正意义上完成了窗口添加操作
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

updateViewLayout(View view,ViewGroup.LayoutParams params)
removeView(View view)

通过ViewRootImpl管理View

你可能感兴趣的:(Android-setContentView())