关于Context,首先想到的是生命周期的不同。今天学习LayoutInflater查看源码,才发现具体的区别。
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源码
- 在Context.java中是抽象方法
- Context的子类是ContextWrapper
- ContextWrapper的子类ContextThemeWrapper
- Activity继承ContextThemeWrapper,Application继承ContextWrapper
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 {
- 先看下ContextWrapper的源码
/**
* 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。
- 下面看下ContextThemeWrapper的源码
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等数据。
- 接下来看下PhoneWindow源码
/**
* 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属性。
- ContextImpl源码
/**
* 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对象截图
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());
}
}