關於Context,首先想到的是生命週期的不一樣。今天學習LayoutInflater查看源碼,才發現具體的區別。java
LayoutInflater部分源碼
/**
* Obtains the LayoutInflater from the given context.
*/
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
複製代碼
從上面代碼觀察,都是調用的Context.getSystemService() 下面看下getSystemService源碼android
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback,
AutofillManager.AutofillClient {
public class Application extends ContextWrapper
implements ComponentCallbacks2 {
複製代碼
/**
* Proxying implementation of Context that simply delegates all of its calls to
* another Context. Can be subclassed to modify behavior without changing
* the original Context.
*/
public class ContextWrapper extends Context {
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
/**
* Set the base context for this ContextWrapper. All calls will then be
* delegated to the base context. Throws
* IllegalStateException if a base context has already been set.
*
* @param base The new base context for this wrapper.
*/
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
@Override
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
}
複製代碼
mBase具體的實現類是ContextImpl,getSystemService返回的Inflater對象是PhoneLayoutInflater。bash
public class ContextThemeWrapper extends ContextWrapper {
public Object getSystemService(String name) {
if ("layout_inflater".equals(name)) {
if (this.mInflater == null) {
this.mInflater = LayoutInflater.from(this.getBaseContext()).cloneInContext(this);
}
return this.mInflater;
} else {
return this.getBaseContext().getSystemService(name);
}
}
}
複製代碼
this.getBaseContext()返回的也是ContextImpl對象,因此LayoutInflater.from(this.getBaseContext())返回的也是PhoneLayoutInflater。 接着調用了cloneInContext(this),設置Activity對象Clone給了Inflate對象中的Context。 而Activity.setContentView()會調用PhoneWindow.setContentView(),由於Activity繼承ContextThemeWrapper,因此會解析Theme和Resource等數據。app
/**
* Android-specific Window.
* <p>
* todo: need to pull the generic functionality out into a base class
* in android.widget.
*
* @hide
*/
public class PhoneWindow extends Window implements MenuBuilder.Callback {
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
@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;
}
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) {
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());
}
}
複製代碼
可見,在建立基本DecorView時,會給Context設置Theme屬性。ide
/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
class ContextImpl extends Context {
......省略......
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
......省略......
}
/**
* Manages all of the system services that can be returned by {@link Context#getSystemService}.
* Used by {@link ContextImpl}.
*/
final class SystemServiceRegistry {
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
}
複製代碼
以上,當LayoutInflater.from(Context context) context 是 Application實例,不會包含Theme等 context 是 Activity實例,會包含Theme等學習
最後看下生成的LayoutInfalter對象截圖ui
public class InflateActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inflate);
LayoutInflater.from(this);
LayoutInflater.from(getApplicationContext());
}
}
複製代碼