Androidソース解析(十七)-->Activityレイアウトロードフロー
52410 ワード
さて、いよいよActivityのレイアウトロードの流れについてお話しします.AndroidシステムでActivityがインタフェースディスプレイの役割を果たしていることはよく知られていますが、androidのもう一つの重要なコンポーネントServiceとは最大の違いですが、このディスプレイのインタフェースの機能はActivityが直接制御しているのでしょうか.インタフェースのレイアウトファイルはどのようにメモリにロードされ、Activityによって管理されますか?AndroidのViewはどんな概念ですか?メモリにロードされたレイアウトファイルはどのように描画されますか?
これらの質問に答えるには、androidのインタフェースのロードと描画の流れを理解する必要があります.ここでは、Activityのレイアウトロードの流れを学びましょう.Activityのレイアウト描画の流れについては、次の記事でご紹介します.
実はActivityのインタフェースレイアウトの管理はすべてWindowオブジェクトによって実現され、Windowオブジェクトは、その名の通りウィンドウオブジェクトであり、Activityはユーザーの観点からウィンドウインスタンスであるため、各Activityには1つのWindowイメージが対応しており、このWindowオブジェクトは表示インタフェースのロードを担当していると想像するのは難しくない.Windowsオブジェクトがどのように異なるインタフェースを表示するかについては、異なるViewコンポーネントを定義することによって異なるインタフェースの表示を実現します.
余計なことを言わないで、私たちが話したActivityの起動プロセスを覚えていますか?よく知らない子供靴は参考にしてください.http://blog.csdn.net/qq_23547831/article/details/51224992ここでは、Activity Management ServicesがActivityの起動要求を受信すると、IApplicationThreadプロセス間通信を通じてApplicationThreadに通知し、handleLauncherActivityメソッドを実行する方法について説明します.
ここでhandleLauncherActivityメソッドの内部でperformLaunchActivityメソッドが呼び出されていることがわかります.このメソッドはActivityを具体的に起動する方法でもあります.具体的な実装ロジックを見てみましょう.
ここでは反射メカニズムによって作成されたActivityがコードから見られ、Activityのattachメソッドが呼び出されていますが、ここでのattachメソッドは何をしているのでしょうか.引き続きattachメソッドの実装ロジックを見てみましょう.
attachメソッドでは、主にmWindowオブジェクトであるActivityのメンバー変数が初期化され、mWindowのメンバーインスタンスがPhoneWindowインスタンスであることがわかり、ActivityがWindowオブジェクトに対応していることも側面から説明されています.Windowsオブジェクトに加えて、Activityの他のメンバー変数も初期化されています.ここでは議論しません.performLaunchActivityメソッドに戻り、Activityのattachメソッドを呼び出した後、次のように呼び出します.
ここでmInstrumentationはクラスInstrumentationであり、各アプリケーションプロセスは1つのInstrumentationと1つのActivity Threadに対応している.Instrumentationは、Activityコールバックのライフサイクルメソッドを具体的に操作するものである.ここでは、そのcallActivity OnCreateメソッドの実装を見てみよう.
ここではコードが簡潔で、preOerformCreateメソッドとpostPerformCreateメソッドはしばらく気にしないで、主な実行ロジックはactivityを呼び出しました.performCreateメソッドActivityのperformCreateメソッドの実装を見てみましょう.
もともとonCreateのライフサイクルメソッドはここでコールバックされていたが、実はここの論理は前のいくつかの文章で述べられており、前の文章を参考にすることもできる.
これでActivityのonCreateメソッドに戻ります.皆さんは普段、onCreateメソッドを書き換えるときに、レイアウトファイルをどのようにロードしますか?ここでは、onCreateメソッドの典型的な書き方を見てみましょう.
私たちがどのように変化しても、私たちのonCreateメソッドは一般的にこの2つの言葉を呼び出すのではないでしょうか.では、ここの2つのコードの分解はどんな意味ですか?まずsuperを見てみましょうonCreateメソッドの実装ロジックは,我々のActivityクラスがActivityと継承しているため,ここのsuper.onCreateメソッドは、呼び出されたActivity.onCreateメソッドです.では、ActivityのonCreateメソッドを見てみましょう.
ActivityのonCreateメソッドは主にいくつかのActivityの初期化操作を行っていることがわかります.もし私たちが自分のActivityでsuperを呼び出さなければ.どうやって?試してみるとAndroid Studioは開いているActivityのonCreateメソッドでsuperを呼び出さなければonCreateメソッドだと、間違って報告されます...木があって間違えた...
superを呼び出さないと表示されます.onCreateメソッドでは、ActivityのperformLaunchActivityでエラーが報告されます.ここのperformLaunchActivityメソッドは、Activityを起動するときにコールバックする方法であることを知っています.メソッド実装中のthrowsのExceptionを探します.
ActivityのperformLaunchActivityメソッドでは、ActivityのonCreateメソッドを呼び出すと判断ロジックが実行されます.ActivityのmCalledがfalseであれば、キャプチャしたばかりの例外が放出されます.このmCalledメンバー変数はいつ付与されますか.ActivityのonCreateメソッドで付与されているので、私たちは自分のActivityを実現するときにsuperを呼び出すしかありません.onCreateメソッドはこの異常を投げ出すことはありません.逆に言えば、私たちは自分のActivivtyを実現するには、onCreateメソッドでsuperを呼び出さなければなりません.onCreateメソッド.
次にonCreateのsetContentViewメソッドを見てみましょう.ここのパラメータはLayoutレイアウトファイルです.ここのsetContentViewメソッドはActivityのsetContentViewです.ActivityのsetContentViewの実装を見てみましょう.
ここでのgetWindowメソッドは、ActivityのmWindowメンバー変数を取得することです.attachメソッドここのmWindowの例がPhoneWindowであることを知っているので、ここで呼び出されたのは実はPhoneWindowのsetConentViewメソッドで、PhoneWindowのsetContentViewがどのように実現されているかを見てみましょう.
ここでmContentParentオブジェクトはViewオブジェクトであり、最初のmContentParentが空であるため、installerDectorメソッドを実行します.ここではinstallerDectorメソッドの具体的な実装を見てみましょう.
ここでmDectorはDectorViewオブジェクトであり、DectorViewはFrameLayoutを継承しているので、ここでmDectorは実際にはFrameLayoutオブジェクトであり、generateDector()メソッドを呼び出して初期化し、generateDectorメソッドの具体的な実装を見てみましょう.
では、newでDectorViewオブジェクトを作成し、installDectorメソッドを見てみましょう.
ここではmContentParentオブジェクトを初期化しました.これはViewオブジェクトです.generateLayoutメソッドを呼び出しました.では、generateLayoutメソッドの具体的な実装を見てみましょう.
ここではLayoutInflaterを呼び出すことによってinflateメソッドは、LayoutInflaterについて、レイアウトファイルをメモリにロードします.inflaterはどのようにレイアウトファイルをロードするかを分析し、コードの分析を通じて、PhoneWindowのいくつかのメンバー変数を発見しました:mDector、mContentRoot、mContentParentの関係mDector->mContentRoot->mContentParent(含む)そして、典型的なレイアウトファイルを見てみましょう.
Activityがロードしたレイアウトファイル全体:screen_simple.xmlは、ViewStubがActivityのtitleBarに対応しており、ここのFrameLayoutでは主に内容を埋め込むために使用されています.
具体的にはLayoutInflaterを見てみましょうinflaterメソッド:
ここでinflateのリロードメソッドを呼び出します..
ソースコードを解析することで、主にxmlファイルをループ解析し、メモリViewオブジェクトに情報を解析することによって、レイアウトファイルで定義された各コンポーネントがメモリに順次解析され、親子Viewの形式で組織されていることがわかります.これにより、指定されたroot Viewによってレイアウトファイル全体で定義されたコンポーネントをすべて解析することができます.解析レイアウトファイルを解析し、setContentViewメソッドに戻り、installDectorメソッドを呼び出した後、次のように呼び出します.
このメソッドの意味は、私たちが渡したクライアントのlayoutIdに対応するレイアウトファイルをmContentParentのサブViewとしてメモリにロードすることであり、私たちのlayoutIdはmContentParentのサブViewとして、mContentParentはmContentRootのサブView、mContentRootはmDectorのサブViewとして、LayoutInflaterのinflateメソッドによってメモリに徐々にロードされ、Activityは独自のPhoneWindowリファレンスを持っています.これは、Activityが定義したレイアウトファイルのリファレンスを持っていることに相当し、Activityのレイアウトファイルがメモリにロードされます.
まとめ: Activityのディスプレイインタフェースの特性は、Windowオブジェクトによって制御される. 各Activityオブジェクトはこの1つのWindowオブジェクトに対応し、Widowオブジェクトの初期化はActivityの起動時に完了し、ActivityのonCreateメソッドを実行する前に完了する. 各Windowオブジェクトの内部には、Activityインタフェースのroot viewであるFrameLayoutタイプのmDectorオブジェクトが存在する. Activityのwindowオブジェクトの例はPhoneWindowオブジェクトです.PhoneWindowオブジェクトのメンバー変数mDector、mContentRoot、mContentParentはすべてViewコンポーネントです.これらの関係は、mDector->mContentRoot->mContentParent->カスタムlayoutView です. LayoutInflater.inflateは主にレイアウトファイルをメモリViewコンポーネントにロードするために使用され、親コンポーネントにロードするように設定することもできます. の典型的なActivityのonCreateメソッドではsuperを呼び出す必要がある.onCreateメソッドとsetContentViewメソッド、superを呼び出さない場合.onCreateメソッドは、Activityを起動するロジックを実行するとエラーが表示され、setContentViewメソッドを実行しないと、Activityには空のページが1つしか表示されません.
さて、Activityのレイアウトロードプロセスについては、ここまで説明しますが、次の記事では、Activityのレイアウト表示プロセスについて説明します.
これらの質問に答えるには、androidのインタフェースのロードと描画の流れを理解する必要があります.ここでは、Activityのレイアウトロードの流れを学びましょう.Activityのレイアウト描画の流れについては、次の記事でご紹介します.
実はActivityのインタフェースレイアウトの管理はすべてWindowオブジェクトによって実現され、Windowオブジェクトは、その名の通りウィンドウオブジェクトであり、Activityはユーザーの観点からウィンドウインスタンスであるため、各Activityには1つのWindowイメージが対応しており、このWindowオブジェクトは表示インタフェースのロードを担当していると想像するのは難しくない.Windowsオブジェクトがどのように異なるインタフェースを表示するかについては、異なるViewコンポーネントを定義することによって異なるインタフェースの表示を実現します.
余計なことを言わないで、私たちが話したActivityの起動プロセスを覚えていますか?よく知らない子供靴は参考にしてください.http://blog.csdn.net/qq_23547831/article/details/51224992ここでは、Activity Management ServicesがActivityの起動要求を受信すると、IApplicationThreadプロセス間通信を通じてApplicationThreadに通知し、handleLauncherActivityメソッドを実行する方法について説明します.
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
// Initialize before creating the activity
WindowManagerGlobal.initialize();
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
if (!r.activity.mFinished && r.startsNotResumed) {
// The activity manager actually wants this one to start out
// paused, because it needs to be visible but isn't in the
// foreground. We accomplish this by going through the
// normal startup (because activities expect to go through
// onResume() the first time they run, before their window
// is displayed), and then pausing it. However, in this case
// we do -not- need to do the full pause cycle (of freezing
// and such) because the activity manager assumes it can just
// retain the current state it has.
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
// We need to keep around the original state, in case
// we need to be created again. But we only do this
// for pre-Honeycomb apps, which always save their state
// when pausing, so we can not have them save their state
// when restarting from a paused state. For HC and later,
// we want to (and can) let the state be saved as the normal
// part of stopping the activity.
if (r.isPreHoneycomb()) {
r.state = oldState;
}
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPause()");
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to pause activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.paused = true;
}
} else {
// If there was an error, for any reason, tell the activity
// manager to stop us.
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
// Ignore
}
}
}
ここでhandleLauncherActivityメソッドの内部でperformLaunchActivityメソッドが呼び出されていることがわかります.このメソッドはActivityを具体的に起動する方法でもあります.具体的な実装ロジックを見てみましょう.
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
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);
}
}
...
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());
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
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);
...
return activity;
}
ここでは反射メカニズムによって作成されたActivityがコードから見られ、Activityのattachメソッドが呼び出されていますが、ここでのattachメソッドは何をしているのでしょうか.引き続き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) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
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;
}
attachメソッドでは、主にmWindowオブジェクトであるActivityのメンバー変数が初期化され、mWindowのメンバーインスタンスがPhoneWindowインスタンスであることがわかり、ActivityがWindowオブジェクトに対応していることも側面から説明されています.Windowsオブジェクトに加えて、Activityの他のメンバー変数も初期化されています.ここでは議論しません.performLaunchActivityメソッドに戻り、Activityのattachメソッドを呼び出した後、次のように呼び出します.
mInstrumentation.callActivityOnCreate(activity, r.state);
ここでmInstrumentationはクラスInstrumentationであり、各アプリケーションプロセスは1つのInstrumentationと1つのActivity Threadに対応している.Instrumentationは、Activityコールバックのライフサイクルメソッドを具体的に操作するものである.ここでは、そのcallActivity OnCreateメソッドの実装を見てみよう.
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
ここではコードが簡潔で、preOerformCreateメソッドとpostPerformCreateメソッドはしばらく気にしないで、主な実行ロジックはactivityを呼び出しました.performCreateメソッドActivityのperformCreateメソッドの実装を見てみましょう.
final void performCreate(Bundle icicle) {
onCreate(icicle);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
もともとonCreateのライフサイクルメソッドはここでコールバックされていたが、実はここの論理は前のいくつかの文章で述べられており、前の文章を参考にすることもできる.
これでActivityのonCreateメソッドに戻ります.皆さんは普段、onCreateメソッドを書き換えるときに、レイアウトファイルをどのようにロードしますか?ここでは、onCreateメソッドの典型的な書き方を見てみましょう.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
私たちがどのように変化しても、私たちのonCreateメソッドは一般的にこの2つの言葉を呼び出すのではないでしょうか.では、ここの2つのコードの分解はどんな意味ですか?まずsuperを見てみましょうonCreateメソッドの実装ロジックは,我々のActivityクラスがActivityと継承しているため,ここのsuper.onCreateメソッドは、呼び出されたActivity.onCreateメソッドです.では、ActivityのonCreateメソッドを見てみましょう.
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
if (mLastNonConfigurationInstances != null) {
mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
}
if (mActivityInfo.parentActivityName != null) {
if (mActionBar == null) {
mEnableDefaultActionBarUp = true;
} else {
mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
}
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
}
mFragments.dispatchCreate();
getApplication().dispatchActivityCreated(this, savedInstanceState);
if (mVoiceInteractor != null) {
mVoiceInteractor.attachActivity(this);
}
mCalled = true;
}
ActivityのonCreateメソッドは主にいくつかのActivityの初期化操作を行っていることがわかります.もし私たちが自分のActivityでsuperを呼び出さなければ.どうやって?試してみるとAndroid Studioは開いているActivityのonCreateメソッドでsuperを呼び出さなければonCreateメソッドだと、間違って報告されます...木があって間違えた...
FATAL EXCEPTION: main Process: com.example.aaron.helloworld, PID: 18001 android.util.SuperNotCalledException: Activity {com.example.aaron.helloworld/com.example.aaron.helloworld.SecondActivity} did not call through to super.onCreate() at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2422) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2528) at android.app.ActivityThread.access$800(ActivityThread.java:169) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1421) at android.os.Handler.dispatchMessage(Handler.java:111) at android.os.Looper.loop(Looper.java:194) at android.app.ActivityThread.main(ActivityThread.java:5552) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)
superを呼び出さないと表示されます.onCreateメソッドでは、ActivityのperformLaunchActivityでエラーが報告されます.ここのperformLaunchActivityメソッドは、Activityを起動するときにコールバックする方法であることを知っています.メソッド実装中のthrowsのExceptionを探します.
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()");
}
ActivityのperformLaunchActivityメソッドでは、ActivityのonCreateメソッドを呼び出すと判断ロジックが実行されます.ActivityのmCalledがfalseであれば、キャプチャしたばかりの例外が放出されます.このmCalledメンバー変数はいつ付与されますか.ActivityのonCreateメソッドで付与されているので、私たちは自分のActivityを実現するときにsuperを呼び出すしかありません.onCreateメソッドはこの異常を投げ出すことはありません.逆に言えば、私たちは自分のActivivtyを実現するには、onCreateメソッドでsuperを呼び出さなければなりません.onCreateメソッド.
次にonCreateのsetContentViewメソッドを見てみましょう.ここのパラメータはLayoutレイアウトファイルです.ここのsetContentViewメソッドはActivityのsetContentViewです.ActivityのsetContentViewの実装を見てみましょう.
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
ここでのgetWindowメソッドは、ActivityのmWindowメンバー変数を取得することです.attachメソッドここのmWindowの例がPhoneWindowであることを知っているので、ここで呼び出されたのは実はPhoneWindowのsetConentViewメソッドで、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 {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
ここでmContentParentオブジェクトはViewオブジェクトであり、最初のmContentParentが空であるため、installerDectorメソッドを実行します.ここではinstallerDectorメソッドの具体的な実装を見てみましょう.
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
...
}
ここでmDectorはDectorViewオブジェクトであり、DectorViewはFrameLayoutを継承しているので、ここでmDectorは実際にはFrameLayoutオブジェクトであり、generateDector()メソッドを呼び出して初期化し、generateDectorメソッドの具体的な実装を見てみましょう.
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
では、newでDectorViewオブジェクトを作成し、installDectorメソッドを見てみましょう.
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
ここではmContentParentオブジェクトを初期化しました.これはViewオブジェクトです.generateLayoutメソッドを呼び出しました.では、generateLayoutメソッドの具体的な実装を見てみましょう.
protected ViewGroup generateLayout(DecorView decor) {
...
// 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!");
}
mDecor.startChanging();
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
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();
}
// 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;
}
ここではLayoutInflaterを呼び出すことによってinflateメソッドは、LayoutInflaterについて、レイアウトファイルをメモリにロードします.inflaterはどのようにレイアウトファイルをロードするかを分析し、コードの分析を通じて、PhoneWindowのいくつかのメンバー変数を発見しました:mDector、mContentRoot、mContentParentの関係mDector->mContentRoot->mContentParent(含む)そして、典型的なレイアウトファイルを見てみましょう.
<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>
Activityがロードしたレイアウトファイル全体:screen_simple.xmlは、ViewStubがActivityのtitleBarに対応しており、ここのFrameLayoutでは主に内容を埋め込むために使用されています.
具体的にはLayoutInflaterを見てみましょうinflaterメソッド:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
ここでinflateのリロードメソッドを呼び出します..
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;
try {
// Look for the root node.
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
final String name = parser.getName();
if (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
+ name);
System.out.println("**************************");
}
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, inflaterContext, attrs, false);
} else {
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);
}
}
if (DEBUG) {
System.out.println("-----> start inflating children");
}
// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true);
if (DEBUG) {
System.out.println("-----> done inflating children");
}
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (Exception e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
} finally {
// Don't retain static reference on context.
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
return result;
}
}
ソースコードを解析することで、主にxmlファイルをループ解析し、メモリViewオブジェクトに情報を解析することによって、レイアウトファイルで定義された各コンポーネントがメモリに順次解析され、親子Viewの形式で組織されていることがわかります.これにより、指定されたroot Viewによってレイアウトファイル全体で定義されたコンポーネントをすべて解析することができます.解析レイアウトファイルを解析し、setContentViewメソッドに戻り、installDectorメソッドを呼び出した後、次のように呼び出します.
mLayoutInflater.inflate(layoutResID, mContentParent);
このメソッドの意味は、私たちが渡したクライアントのlayoutIdに対応するレイアウトファイルをmContentParentのサブViewとしてメモリにロードすることであり、私たちのlayoutIdはmContentParentのサブViewとして、mContentParentはmContentRootのサブView、mContentRootはmDectorのサブViewとして、LayoutInflaterのinflateメソッドによってメモリに徐々にロードされ、Activityは独自のPhoneWindowリファレンスを持っています.これは、Activityが定義したレイアウトファイルのリファレンスを持っていることに相当し、Activityのレイアウトファイルがメモリにロードされます.
まとめ:
さて、Activityのレイアウトロードプロセスについては、ここまで説明しますが、次の記事では、Activityのレイアウト表示プロセスについて説明します.