第一章 Activity启动和视图

简介:这一章主要研究Activity—》Window—》DecoView--》ContentView的过程。即初始化Activity界面过程。核心功能是分析setContentView原理。

关键问题:

1)Activity与Window对应关系如何?

2)Window是怎么生成的?有什么作用?对应的区域是多少?

3)DecoView有什么作用?对应的区域是多少?

4)ContentView(int resId)是怎么生成和添加子视图的?有哪些步骤?

5)LayoutInflater是怎么生成的?依赖什么条件吗?

 

1.0 界面层级关系

Activity的UI结构。

  • 每个Activity中都包含一个Window对象,通常,Android中的Window是由PhoneWindow实现的。
  • PhoneWindow又将一个DecorView设置为整个窗口的根View(DecorView是一个ViewGroup)。
  • DecorView里面又有两个View,一个是用作title或者导航栏的,

另外一个是ID为content的FrameLayout用来装我们加写的Xml文件布局的View。即setContentView

1.1 Activity初始化

Activity的创建离不开ActivityThread。

ActiveThread是每一个应用程序所在进程的主线程。

//ActivityThread有一个ArrayList存储启动的 Activity列表。

final ArrayList<ActivityClientRecord> mRelaunchingActivities
       
= new ArrayList<ActivityClientRecord>();

 

1.1.1 ActivityClientRecord的存储结构。

ActivityClientRecord存储启动的Activity相关信息。

public final Activity startActivityNow(Activity parent, String id,

        Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,

        Activity.NonConfigurationInstances lastNonConfigurationInstances) {

        //保存启动信息到ActivityClientRecord对象中

        ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;

            r.ident = 0;

            r.intent = intent;

            r.state = state;

            r.parent = parent;

            r.embeddedID = id;

            r.activityInfo = activityInfo;

            r.lastNonConfigurationInstances = lastNonConfigurationInstances;

        if (localLOGV) {

            ComponentName compname = intent.getComponent();

            String name;

            if (compname != null) {

                name = compname.toShortString();

            } else {

                name = "(Intent " + intent + ").getComponent() returned null";

            }

            Slog.v(TAG, "Performing launch: action=" + intent.getAction()

                    + ", comp=" + name

                    + ", token=" + token);

        }

        //调用performLaunchActivity执行启动一个新的Activity

        return performLaunchActivity(r, null);

    }

ActivityClientRecord存储什么内容呢?有什么作用?

存储Activity相关的信息,包括

 

static final class ActivityClientRecord {

        IBinder token;   //Binder对象

        int ident;

        Intent intent;   //Intent对象(意图)

        String referrer;

        IVoiceInteractor voiceInteractor;

        Bundle state;   //Bundle参数

        PersistableBundle persistentState;

        Activity activity;  //创建的Activity对象

        Window window; //Activity的窗口对象

        Activity parent;  //Activity的父Activity

        String embeddedID;

        Activity.NonConfigurationInstances lastNonConfigurationInstances;

              //Activity执行的状态信息

        boolean paused;

        boolean stopped;

        boolean hideForNow;

        Configuration newConfig;

        Configuration createdConfig;

        Configuration overrideConfig;

        // Used for consolidating configs before sending on to Activity.

        private Configuration tmpConfig = new Configuration();

        ActivityClientRecord nextIdle;

 

        ProfilerInfo profilerInfo;

 

        ActivityInfo activityInfo;

        CompatibilityInfo compatInfo;

        LoadedApk packageInfo;

 

        List<ResultInfo> pendingResults;

        List<ReferrerIntent> pendingIntents;

 

        boolean startsNotResumed;

        boolean isForward;

        int pendingConfigChanges;

        boolean onlyLocalRequest;

 

        Window mPendingRemoveWindow;

        WindowManager mPendingRemoveWindowManager;

        boolean mPreserveWindow;

 

        // Set for relaunch requests, indicates the order number of the relaunch operation, so it

        // can be compared with other lifecycle operations.

        int relaunchSeq = 0;

 

        // Can only be accessed from the UI thread. This represents the latest processed message

        // that is related to lifecycle events/

        int lastProcessedSeq = 0;

……

}

1.1.2 启动Activity

ActivityThread.java中startActivityNow函数:

通过调用performLaunchActivity函数启动Activity.

现在来看看启动Activity的操作。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

。。。。。。
//1)采用Instrumentation生成一个新的Activity实例  

      Activity activity = null;

    try {

        java.lang.ClassLoader cl = r.packageInfo.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);

        }

    }



//2)Activity运行上下文初始化
//Activity依赖的上下文监测:如果归属的Application未生成,则生成和初始化Application对象(这种跨进程调用需要)
    try {

        Application app = r.packageInfo.makeApplication(false, mInstrumentation);



        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);

        if (localLOGV) Slog.v(

                TAG, r + ": app=" + app

                + ", appName=" + app.getPackageName()

                + ", pkg=" + r.packageInfo.getPackageName()

                + ", comp=" + r.intent.getComponent().toShortString()

                + ", dir=" + r.packageInfo.getAppDir());



//Activity的BaseContext监测:如果不存在进行创建 
        if (activity != null) {

            Context appContext = createBaseContextForActivity(r, activity);

            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());

            Configuration config = new Configuration(mCompatConfiguration);

            if (r.overrideConfig != null) {

                config.updateFrom(r.overrideConfig);

            }

            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "

                    + r.activityInfo.name + " with config " + config);

            Window window = null;

            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {

                window = r.mPendingRemoveWindow;

                r.mPendingRemoveWindow = null;

                r.mPendingRemoveWindowManager = null;

            }
      //3)将Activity对象关联BaseContext。创建PhoneWindow对象。

            activity.attach(appContext, this, getInstrumentation(), r.token,

                    r.ident, app, r.intent, r.activityInfo, title, r.parent,

                    r.embeddedID, r.lastNonConfigurationInstances, config,

                    r.referrer, r.voiceInteractor, window);



            if (customIntent != null) {

                activity.mIntent = customIntent;

            }

            r.lastNonConfigurationInstances = null;

            activity.mStartedActivity = false;

            int theme = r.activityInfo.getThemeResource();

            if (theme != 0) {

                activity.setTheme(theme);

            }

//4)回调Activity的onCreate生命周期
activity.mCalled = false;

    if (r.isPersistable()) {

        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);

    } else {

        mInstrumentation.callActivityOnCreate(activity, r.state);

    }

    if (!activity.mCalled) {

        throw new SuperNotCalledException(

            "Activity " + r.intent.getComponent().toShortString() +

            " did not call through to super.onCreate()");

    }

    r.activity = activity;

    r.stopped = true;

    if (!r.activity.mFinished) {

        activity.performStart();

        r.stopped = false;

    }
//回调onRestoreInstanceState处理,读取缓存的数据

    if (!r.activity.mFinished) {

        if (r.isPersistable()) {

            if (r.state != null || r.persistentState != null) {

                mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,

                        r.persistentState);

            }

        } else if (r.state != null) {

            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);

        }

    }
    //5)调用Activity onCreate后续处理?到底是什么处理呢?标题栏的处理,设置标题和颜色。

    if (!r.activity.mFinished) {

        activity.mCalled = false;

        if (r.isPersistable()) {

            mInstrumentation.callActivityOnPostCreate(activity, r.state,

                    r.persistentState);

        } else {

            mInstrumentation.callActivityOnPostCreate(activity, r.state);

        }

        if (!activity.mCalled) {

            throw new SuperNotCalledException(

                "Activity " + r.intent.getComponent().toShortString() +

                " did not call through to super.onPostCreate()");

        }

    }

}

r.paused = true;
       //6)保存新创建的ActivityClientRecord

        mActivities.put(r.token, r);



    } catch (SuperNotCalledException e) {

        throw e;



    } catch (Exception e) {

        if (!mInstrumentation.onException(activity, e)) {

            throw new RuntimeException(

                "Unable to start activity " + component

                + ": " + e.toString(), e);

        }

    }

    return activity;

}

关键在于调用activity.attach处理。

1.2 PhoneWindow的初始化

Activity.java

我们来看看attach处理。

1.2.1 Activity.attach

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) {
     //1)关联BaseContext
    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);

  //2)新建PhoneWindow.PhoneWindow和Activity相关,因此上下文为Activity.
只有主活动窗口使用Deor上下文,所有其他窗口依赖于赋予它们的任何上下文。

    mWindow = new PhoneWindow(this, window);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    //问题:PhoneWindow的LayoutInflater对象怎么生成的呢?
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }

    //3)初始化当前Activity的基本信息
if (info.uiOptions != 0) {

        mWindow.setUiOptions(info.uiOptions);

    }

    mUiThread = Thread.currentThread();



    mMainThread = aThread;

    mInstrumentation = instr;

    mToken = token;

    mIdent = ident;

    mApplication = application;

    mIntent = intent;

    mReferrer = referrer;

    mComponent = intent.getComponent();

    mActivityInfo = info;

    mTitle = title;

    mParent = parent;

    mEmbeddedID = id;

    mLastNonConfigurationInstances = lastNonConfigurationInstances;

    if (voiceInteractor != null) {

        if (lastNonConfigurationInstances != null) {

            mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;

        } else {

            mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,

                    Looper.myLooper());

        }

    }



    mWindow.setWindowManager(

            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),

            mToken, mComponent.flattenToString(),

            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);

    if (mParent != null) {

        mWindow.setContainer(mParent.getWindow());

    }

    mWindowManager = mWindow.getWindowManager();

    mCurrentConfig = config;

}

 

1.2.2 问题:PhoneWindow中有一个LayoutInflater,这个是什么时候生成的呢?

这个实在PhoneWindow构造函数创建的时候生成的。上下文对应的是Activity。

 

PhoneWindow.java

           //有一个成员为DecorView

           private DecorView mDecor;
//设置窗口内容存放的视图,要么是DecorView自身,或者是DecorView的字视图--包含保存存放内容的子视图   // This is the view in which the window contents are placed. It is either // mDecor itself, or a child of mDecor where the contents go. ViewGroup mContentParent;

public PhoneWindow(Context context) {
    super(context);
    mLayoutInflater = LayoutInflater.from(context);
}

LayoutInflater在PhoneWindow初始化的时候创建的。

1.3 DecorView初始化

常见问题:

1)DecorView什么时候初始化?

2)DecorView和ContentParent是同一个东西吗?存储内容有什么不同?

3)FEATURE_CONTENT_TRANSITIONS对ContentView的初始化有什么影响?

FEATURE_CONTENT_TRANSITIONS是Activity切换的过渡动画。在这种情况下,

不但要进行setContentView初始化目标页面,还需要对切换效果播放一个动画。

4)setContentView是直接从XML将得到的内容视图添加到DecorView吗?

5)如果Activity初始化时不调用setContentView,页面是否能够显示?

1.3.1 Activity. setContentView

这是窗口的顶视图,包含窗口装饰。

Activity.java 看看setContentView入口处理:

Step1

/**

* 将布局资源添加到Activity内容区。资源(XML)将被展开inflated形成子视图,添加到Activity顶层视图中。

*/
/**
 * Set the activity content from a layout resource.  The resource will be
 * inflated, adding all top-level views to the activity.
 *
 * @param layoutResID Resource ID to be inflated.
 *
 * @see #setContentView(android.view.View)
 * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
 */

public void setContentView(@LayoutRes int layoutResID) {
      
//1)将资源视图添加到PhoneWindow

    getWindow().setContentView(layoutResID);
     
 //2)初始化DecorView(如果没有初始化)ActionBar

    initWindowDecorActionBar();
}

 

 

1.3.2 PhoneView. setContentView

Step2

 

我们Activity对象继承Activity类,在onCreate中,会调用setContentView方法设置页面内容。

Note: FEATURE_CONTENT_TRANSITIONS

@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.
注意:可以在安装窗口装饰器的过程中设置FEATURE_CONTENT_TRANSITIONS。在发生这种情况之前不要设置这个特性。

    if (mContentParent == null) {

        //1}内容区父视图为空时,进行安装操作即DecorView的初始化。然后展开布局资源,添加到顶级视图中
     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 {
   //3)layoutResId展开并且添加到内容区父视图中

        mLayoutInflater.inflate(layoutResID, mContentParent);

    }

    mContentParent.requestApplyInsets();

    final Callback cb = getCallback();

    if (cb != null && !isDestroyed()) {

        cb.onContentChanged();

    }

    mContentParentExplicitlySet = true;

}

 

1.3.3 PhoneView. installDecor

Step3: 接着分析installDecor。安装DecorView

private void installDecor() {

    mForceDecorInstall = false;

    //1.创建DecorView.如果没有初始化则进行创建;如果已经存在,则将其关联当前PhoneWindow
if (mDecor == null) {

      //Décor为空生成一个新的DecorView
    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);



        // Set up decor part of UI to ignore fitsSystemWindows if appropriate.

        mDecor.makeOptionalFitsSystemWindows();
        final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                R.id.decor_content_parent);

        if (decorContentParent != null) {
            mDecorContentParent = decorContentParent;
            mDecorContentParent.setWindowCallback(getCallback());
            if (mDecorContentParent.getTitle() == null) {
                mDecorContentParent.setWindowTitle(mTitle);
            }

            final int localFeatures = getLocalFeatures();
            for (int i = 0; i < FEATURE_MAX; i++) {

                if ((localFeatures & (1 << i)) != 0) {

                    mDecorContentParent.initFeature(i);

                }

            }

。。。。。。

  

    }

}

 

在其中,会生成DecorView和Contentparent。那么我们继续分析

 

1.3.4 PhoneView. generateDecor

常见问题:

  1. DecorView的上下文从何获取?
  2. DecorView

 

protected DecorView generateDecor(int featureId) {
     //系统进程没有Application上下文,在这种情况下,我们需要直接使用我们拥有的上下文。否则,我们需要Application程序上下文,因此我们不依附于该Activity。
    // 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) {

        Context applicationContext = getContext().getApplicationContext();

        if (applicationContext == null) {

            context = getContext();

        } else {

            context = new DecorContext(applicationContext, getContext().getResources());

            if (mTheme != -1) {

                context.setTheme(mTheme);

            }

        }

    } else {

        context = getContext();

    }

    return new DecorView(context, featureId, this, getAttributes());

}

新创建一个DecorView对象。

 

1.3.5 PhoneWindow. generateLayout

 

常见问题:

1.ContentParent与DecorView关系?

2.ContentParent是否需要依赖DecorView?

3. ContentParent层级结构如何?

4.用户是否可以替代ContentParent?

5.DecorView和ContentParent是视图吗?

两者都是容器,是FrameLayout

 

protected ViewGroup generateLayout(DecorView decor) {

    // Apply data from current theme.

    // Inflate the window 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;

    } 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) {

            TypedValue res = new TypedValue();

            getContext().getTheme().resolveAttribute(

                    R.attr.dialogCustomTitleDecorLayout, res, true);

            layoutResource = res.resourceId;

        } 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) {

            TypedValue res = new TypedValue();

            getContext().getTheme().resolveAttribute(

                    R.attr.dialogTitleDecorLayout, res, true);

            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!");

    }



   //1)展开视图资源添加到DecorView

    mDecor.startChanging();

    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

   
//2)初始化ContentParent. ContentParent通过一个固定的ID(android.R.id.content)从DecorView中获取到。   

    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

    if (contentParent == null) {

        throw new RuntimeException("Window couldn't find content container view");

    }

    mDecor.finishChanging();
。。。。。。

    //3)设置标题和背景

    return contentParent;

}



那么在布局中到底是怎么实现的呢?

1.3.6 ContentParent的布局

找到系统资源R.layout.screen_simple;

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

 

DecorView根布局里面添加了类似上面的布局,线性布局LinearLaout里包含两个组件,ViewStub是懒加载,默认不显示,

ContentParent: FrameLayout是什么呢?看看id=content,就是我们找到的父容器 contentParent。那么这个父容器 contentParent有什么作用呢?

用户定义的视图内容需要添加到contentParent中。

 

PhoneView.java

@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 {

        mLayoutInflater.inflate(layoutResID, mContentParent);

    }

    mContentParent.requestApplyInsets();

    final Callback cb = getCallback();

    if (cb != null && !isDestroyed()) {

        cb.onContentChanged();

    }

    mContentParentExplicitlySet = true;

}

 

关于WindowFeature

1.关于requestWindowFeature(Window.FEATURE_NO_TITLE); 去除标题栏的疑问,如果你自己的xxxActivity是继承自Activity,那么恭喜你使用以上方法可以去除标题栏,如果你自己的xxxActivity是继承自AppCompatActivity或者ActionBarActivity,那么很遗憾告诉你,此次系统默认的标题栏已经在主题中去除,此时显示的标题栏是ActionBar导航栏,如果需要去除导航栏,你可以通过如下代码:getSupportActionBar().hide();来隐藏导航栏

2.requestWindowFeature(Window.FEATURE_NO_TITLE);方法需要在 setContentView方法之前使用,由上面 Step5分析可得,设置Activity Window 特征是在setContentView方法中设置的,因此,如果需要改变Activity Window窗口特征,需要在setContentView方法之前。其实这里有疑问???为什么设置全屏的方法

1.3.7 setContentView(View view)

基本过程和setContentView(int layoutResID)相同。

  1. 安装DecorView;
  2. 初始化Contentparent;
  3. ContentParent中添加内容视图view(layoutResID是通过LayoutInflater展开以后生成子视图,然后添加到ContentParent中)

 

@Override

public void setContentView(View view) {

    setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));

}



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

从前面ActivityThread启动Activity过程可知,Activity.attach的以后,会进行回调Activity

生命周期onCreate。这样回调用到我们自己创建的Activity的onCreate处理。在onCreate时,

我们一般通过调用setContentView(int layoutResID);来设置页面内容。

 

1.4 窗口特征和DecorView区域

1.4.1 PhoneVindow. setContentView

@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)) {
        //含有Activity切换过渡动画
        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;
}

通过Sence执行过渡动画。

1.4.2 PhoneWindow. transitionTo

       执行Activity过渡动画。

private void transitionTo(Scene scene) {
     //1)如果目标页面的场景未进行初始化则先初始化目标页面(需要进入的页面)
    if (mContentScene == null) {
        scene.enter();
    } else {
        //2)如果场景已存在直接播放过渡动画
        mTransitionManager.transitionTo(scene);
    }
    mContentScene = scene;
}

 

 

1.4.3 Sence.enter

进入场景,播放Activity过渡动画。

public void enter() {
    //1)添加布局到场景中
    // Apply layout change, if any
    if (mLayoutId > 0 || mLayout != null) {
        //清除原ContentParent中的所有子视图
     // empty out parent container before adding to it
        getSceneRoot().removeAllViews();
        //重新添加最新的视图内容
        if (mLayoutId > 0) {
            LayoutInflater.from(mContext).inflate(mLayoutId, mSceneRoot);
        } else {
            mSceneRoot.addView(mLayout);
        }
    }

    //2)通知进入下一个场景,播放过渡动画。子类可以覆盖场景配置(过渡动画的进入动画)
    // Notify next scene that it is entering. Subclasses may override to configure scene.
    if (mEnterAction != null) {
        mEnterAction.run();
    }
    setCurrentScene(mSceneRoot, this);
}

SeneRoot即ContentParent。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值