美文网首页
Android setContentView做了什么

Android setContentView做了什么

作者: 青果果 | 来源:发表于2018-04-02 15:00 被阅读0次

    setContentView( )方法是在熟悉不过了
    那到底后面源码是怎样的呢

    用 android.app包下的Activity为例
    V7 包下的AppCompatActivity 还有点不太一样

    点击去看setContentView方法
    实际是调用了Window的setContentView方法
    而mWindow的初始化是在Activity的attach()方法中new出来的PhoneWindow
    那么就看PhoneWindow的setContentView()方法

    public void setContentView(@LayoutRes int layoutResID) {
            getWindow().setContentView(layoutResID);
            initWindowDecorActionBar();
        }
    
    public Window getWindow() {
            return 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, ActivityConfigCallback activityConfigCallback) {
            attachBaseContext(context);
    
            mFragments.attachHost(null /*parent*/);
             //Window 是抽象类   那就看PhoneWindow类的setContentView方法
            mWindow = new PhoneWindow(this, window, activityConfigCallback);
          ......
     }
    

    PhoneWindow类的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.
            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 {
                //这里看到把传进来的layoutResID 布局加载到mContentParent里
                mLayoutInflater.inflate(layoutResID, mContentParent);
            }
            mContentParent.requestApplyInsets();
            final Callback cb = getCallback();
            if (cb != null && !isDestroyed()) {
                cb.onContentChanged();
            }
            mContentParentExplicitlySet = true;
        }
    

    代码太多,就不全部贴出来了,installDecor()方法里面
    mContentParent 是由generateLayout()方法来赋值

    if (mContentParent == null) {
                mContentParent = generateLayout(mDecor);// mDecor---- DecorView
    
       
    

    generateLayout()方法里面, mDecor会先加载系统的布局layoutResource

    然后查找里面的com.android.internal.R.id.content 返回给 mContentParent

    protected ViewGroup generateLayout(DecorView decor) {
            int layoutResource;
            int features = getLocalFeatures();
            // System.out.println("Features: 0x" + Integer.toHexString(features));
            if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
                layoutResource = R.layout.screen_swipe_dismiss;
                setCloseOnSwipeEnabled(true);
            } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
                if (mIsFloating) {
                    TypedValue res = new TypedValue();
                    getContext().getTheme().resolveAttribute(
                            R.attr.dialogTitleIconsDecorLayout, res, true);
                    layoutResource = res.resourceId;
                } else {
                    layoutResource = R.layout.screen_title_icons;
                }
                // XXX Remove this once action bar supports these features.
                removeFeature(FEATURE_ACTION_BAR);
                // System.out.println("Title Icons!");
            } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
                    && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
                // Special case for a window with only a progress bar (and title).
                // XXX Need to have a no-title version of embedded windows.
                layoutResource = R.layout.screen_progress;
                // System.out.println("Progress!");
            } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
                // Special case for a window with a custom title.
                // If the window is floating, we need a dialog layout
                if (mIsFloating) {
                 // ....
                } else {
                    layoutResource = R.layout.screen_custom_title;
                }
                // XXX Remove this once action bar supports these features.
                removeFeature(FEATURE_ACTION_BAR);
            } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
                // If no other features and not embedded, only need a title.
                // If the window is floating, we need a dialog layout
                if (mIsFloating) {
                     // ...
                    layoutResource = res.resourceId;
                } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
                    layoutResource = a.getResourceId(
                            R.styleable.Window_windowActionBarFullscreenDecorLayout,
                            R.layout.screen_action_bar);
                } else {
                    layoutResource = R.layout.screen_title;
                }
                // System.out.println("Title!");
            } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
                layoutResource = R.layout.screen_simple_overlay_action_mode;
            } else {
                // Embedded, so no decoration is needed.
                layoutResource = R.layout.screen_simple;
                // System.out.println("Simple!");
            }
            // Inflate the window decor.
            //mDecor会先加载布局
            mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
        
            // ID_ANDROID_CONTENT  com.android.internal.R.id.content
            ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    
            if (contentParent == null) {
                throw new RuntimeException("Window couldn't find content container view");
            }
        //...省略了代码
        return contentParent;
    }
    

    PhoneWindow的generateLayout中加载系统资源
    是mDecor调用了onResourcesLoaded方法

    public class PhoneWindow extends Window implements MenuBuilder.Callback {
    ...
    // This is the top-level view of the window, containing the window decor.
    private DecorView mDecor;
    ...
    protected DecorView generateDecor(int featureId) {
       ...
       mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
       ...
    }
    
    void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
            mStackId = getStackId();
            if (mBackdropFrameRenderer != null) {
                loadBackgroundDrawablesIfNeeded();
                mBackdropFrameRenderer.onResourcesLoaded(
                        this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
                        mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
                        getCurrentColor(mNavigationColorViewState));
            }
    
            mDecorCaptionView = createDecorCaptionView(inflater);
            final View root = inflater.inflate(layoutResource, null);
            if (mDecorCaptionView != null) {
                if (mDecorCaptionView.getParent() == null) {
                    addView(mDecorCaptionView,
                            new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
                }
                mDecorCaptionView.addView(root,
                        new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
            } else {
                // Put it below the color views.
                addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
            }
            mContentRoot = (ViewGroup) root;
            initializeElevation();
        }
    
    系统的布局layoutResource,主题不同,布局不同
    public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
    
            ......
    
      }
    

    当在Activity中调用setContentView() 方法的时候
    会获取到Window,然后创建一个DecorView (是FrameLayout 子类)
    DecorView 里面有一个系统默认的布局,其中有个id为 com.android.internal.R.id.content的ViewGroup
    然后把我们Activity的布局加载到这里面

    View.png

    相关文章

      网友评论

          本文标题:Android setContentView做了什么

          本文链接:https://www.haomeiwen.com/subject/hzzthftx.html