android高级进阶

android中xml布局文件加载流程

2017-12-13  本文已影响11人  android的那点事

简述

当我们在XML写好布局,然后通过Activity中onCreate方法中setContentView(R.layout.activity_path_measure);就可以把布局加载进入,然后把布局界面展现在我们眼前.十分简单,但是你是否了解它加载的过程........先让我们看一下图吧


image.png

加载过程

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //加载布局文件
    setContentView(R.layout.activity_path_measure);
}

在这里我们主要看一下 getWindow().setContentView(layoutResID);这个方法

这mWindow又是什么玩意呢,我们慢慢找,我们可以在attach(,,,) 方法中找到mWindow生成方法;

     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) {
    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);
    //这里就是mWindow的创建
    mWindow = new PhoneWindow(this, window);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    //在这里省略了好多代码..........
  }

从上面代码我们可以看出,mWindow其实是一个PhoeWindow,它是一个窗体,继承Window;

在这里我们得找到PhoeWindow这个类,然后找到setContentView这个方法,看到底是怎么一个加载过程,看一下PhoeWindow中setContentView的源码;

    @Override
public void setContentView(int layoutResID) {
    // 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.

    //这个是第一步(1),mContentParent是什么玩意,其实他就是一个 ViewGroup容器,待把布局加载进去
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
  
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
    //这是第二步(2)
      //把布局加载进去,这个方法这里我就不深入了,以后有时间我单独讲一下LayoutInflater.inflate
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

从上面的源码我们分析得到,加载布局主要有二个步骤,刚开始mContentParent肯定是null,为null时走 installDecor();这个方法,这个后面会深入的讲解,不为null走mContentParent.removeAllViews()这个方法,这个方法很好理解,就是清空所有已加载的View,第二步就是把布局加载mContentParent中,mLayoutInflater.inflate(layoutResID, mContentParent);这个方法这里我不深入去讲解,有时间后面再单独拿出来讲解;

从上面源码,我们可以看到mContentParent是在这里赋值的,我们好好研究generateLayout(mDecor)这个方法,在研究这个方法前,我们把搞清楚mDecor又是什么玩意;

从上面源码可以看出,mDecor就是 DecorView, DecorView是一个FrameLayout,看它的源码就很直观;

    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {

    /* package */int mDefaultOpacity = PixelFormat.OPAQUE;

    /** The feature ID of the panel, or -1 if this is the application's DecorView */
    private final int mFeatureId;

    private final Rect mDrawingBounds = new Rect();

    private final Rect mBackgroundPadding = new Rect();

    private final Rect mFramePadding = new Rect();

    private final Rect mFrameOffsets = new Rect();

    //又省略N多代码.......................................

}

从上面源码我们可以contentParent就是com.android.internal.R.id.content这个ID的FrameLayout; 而com.android.internal.R.id.content这个ID就是上面layoutResource布局中FrameLayout;在这里还是让大家看一下layoutResource布局文件吧,

  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
          android:inflatedId="@+id/action_mode_bar"
          android:layout="@layout/action_mode_bar"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:theme="?attr/actionBarTheme" />

//contentParent就是这个玩意啊...............................
<FrameLayout

     android:id="@android:id/content"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:foregroundInsidePadding="false"
     android:foregroundGravity="fill_horizontal|top"
     android:foreground="?android:attr/windowContentOverlay" />

</LinearLayout>

好了,我们终于了解到contentParent是什么了,我们回到前面讲的installDecor()方法,这样就可以进行第二个步骤了 mLayoutInflater.inflate(layoutResID, mContentParent);就我们的布局加载到contentParent这个FrameLayout去了.差不多就这些了!总的看一下以下图;


image.png

本人做android开发多年,以后会陆续更新关于android高级UI,NDK开发,性能优化等文章,更多请关注我的微信公众号:谢谢!

image
上一篇下一篇

猜你喜欢

热点阅读