setContentView流程

Posted cao_null

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了setContentView流程相关的知识,希望对你有一定的参考价值。

AppCompatActivity的方法实际是调用

先获取AppCompatDelegate委托类,最终调用AppCompatDelegateImplV9,只分析最常用的方法:

所有方法都用到了ensureSubDecor

private void ensureSubDecor() 
  if (!mSubDecorInstalled) //确保执行一次
      mSubDecor = createSubDecor();

      // If a title was set before we installed the decor, propagate it now
      CharSequence title = getTitle();
      if (!TextUtils.isEmpty(title)) 
          onTitleChanged(title);//设置title
      

      applyFixedSizeWindow();

      onSubDecorInstalled(mSubDecor);

      mSubDecorInstalled = true;

      // Invalidate if the panel menu hasn't been created before this.
      // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
      // being called in the middle of onCreate or similar.
      // A pending invalidation will typically be resolved before the posted message
      // would run normally in order to satisfy instance state restoration.
      PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
      if (!isDestroyed() && (st == null || st.menu == null)) 
          invalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR);
      
  

创建SubDecor
private ViewGroup createSubDecor() 
  TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);

  if (!a.hasValue(R.styleable.AppCompatTheme_windowActionBar)) 
      a.recycle();
      throw new IllegalStateException(
              "You need to use a Theme.AppCompat theme (or descendant) with this activity.");
  

  if (a.getBoolean(R.styleable.AppCompatTheme_windowNoTitle, false)) 
      requestWindowFeature(Window.FEATURE_NO_TITLE);
   
...省略

  mIsFloating = a.getBoolean(R.styleable.AppCompatTheme_android_windowIsFloating, false);
  a.recycle();//设置主题

  // Now let's make sure that the Window has installed its decor by retrieving it
  mWindow.getDecorView();

  final LayoutInflater inflater = LayoutInflater.from(mContext);
  ViewGroup subDecor = null;


  if (!mWindowNoTitle) 
      if (mIsFloating) 
          // If we're floating, inflate the dialog title decor
          subDecor = (ViewGroup) inflater.inflate(
                  R.layout.abc_dialog_title_material, null);

          ...省略生成设置subDecor

  // Now set the Window's content view with the decor
  mWindow.setContentView(subDecor);//设置在这

  contentView.setAttachListener(new ContentFrameLayout.OnAttachListener() 
      @Override
      public void onAttachedFromWindow() 

      @Override
      public void onDetachedFromWindow() 
          dismissPopups();
      
  );

  return subDecor;
最终设置contentview
@Override
    public void setContentView(View view, ViewGroup.LayoutParams params) 
        // 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();
         else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) 
            mContentParent.removeAllViews();
        

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) 
            view.setLayoutParams(params);
            final Scene newScene = new Scene(mContentParent, view);
            transitionTo(newScene);
         else 
            mContentParent.addView(view, params);//addview在这
        
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) 
            cb.onContentChanged();
        
        mContentParentExplicitlySet = true;
    
安装Decor
private void installDecor() 
  mForceDecorInstall = false;
  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(mDecor);//生成布局

      。。。省略
      
  
创建的DecorView是一个FrameLayout
protected DecorView generateDecor(int featureId) 
  // System process doesn't have application context and in that case we need to directly use
  // the context we have. Otherwise we want the application context, so we don't cling to the
  // activity.
  Context context;
  if (mUseDecorContext) //Activity才为true
      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());
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks 

生成布局

protected ViewGroup generateLayout(DecorView decor) 
  // Apply data from current theme.

  ...省略跟主题和样式相关

 else 
  // Embedded, so no decoration is needed.
  layoutResource = R.layout.screen_simple;
  // System.out.println("Simple!");


  mDecor.startChanging();
  mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

  ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);//contentParent就是id为content的FrameLayout
  if (contentParent == null) 
      throw new RuntimeException("Window couldn't find content container view");
  

  if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) 
      ProgressBar progress = getCircularProgressBar(false);
      if (progress != null) 
          progress.setIndeterminate(true);
      
  

  if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) 
      registerSwipeCallbacks(contentParent);
  

  // Remaining setup -- of background and title -- that only applies
  // to top-level windows.
  if (getContainer() == null) 
      final Drawable background;
      if (mBackgroundResource != 0) 
          background = getContext().getDrawable(mBackgroundResource);
       else 
          background = mBackgroundDrawable;
      
      mDecor.setWindowBackground(background);

      final Drawable frame;
      if (mFrameResource != 0) 
          frame = getContext().getDrawable(mFrameResource);
       else 
          frame = null;
      
      mDecor.setWindowFrame(frame);

      mDecor.setElevation(mElevation);
      mDecor.setClipToOutline(mClipToOutline);

      if (mTitle != null) 
          setTitle(mTitle);
      

      if (mTitleColor == 0) 
          mTitleColor = mTextColor;
      
      setTitleColor(mTitleColor);
  

  mDecor.finishChanging();

  return contentParent;

查看布局文件

<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" />
    <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>

嵌套关系如图

AppCompatDelegateImplV9中生成的view布局 abc_screen_simple

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<android.support.v7.widget.FitWindowsLinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/action_bar_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:fitsSystemWindows="true">

    <android.support.v7.widget.ViewStubCompat
        android:id="@+id/action_mode_bar_stub"
        android:inflatedId="@+id/action_mode_bar"
        android:layout="@layout/abc_action_mode_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <include layout="@layout/abc_screen_content_include" />

</android.support.v7.widget.FitWindowsLinearLayout>

嵌套关系图最后加到content中

 

最后看

@Override
    public void setContentView(View view, ViewGroup.LayoutParams params) 
        // 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();
         else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) 
            mContentParent.removeAllViews();
        

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) 
            view.setLayoutParams(params);
            final Scene newScene = new Scene(mContentParent, view);
            transitionTo(newScene);
         else 
            mContentParent.addView(view, params);
        
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) 
            cb.onContentChanged();
        
        mContentParentExplicitlySet = true;
    

分析到这基本上流程已经梳理清晰了。

总的布局结构

以上是关于setContentView流程的主要内容,如果未能解决你的问题,请参考以下文章

android setContentView处理流程

Activity的setContentView的流程

setContentView流程

setContentView流程

Android-Activity中setContentView流程解析

小白都看得懂的布局加载流程