四大组件的context的研究
看到同事发了一个这个图。大致有点感觉 ,但是理解的不透彻。三个月后。10.14号。等我多做点东西,对这些部件了解深了再来写一个总结吧。
今天10.14号,交作业了。这个就是安卓四大组件加一个Application可以实现的功能嘛。
其实呢,上述的这个功能呢,都与context有关。context在哪些地方用到了呢?弹出Toast、弹出dialog,启动Activity、启动Service、发送广播、操作数据库,Inflate布局等等都需要用到Context。context就是实现功能的情景。
从这个继承关系图中,contextImpl是抽象类context的具体实现类,contextwrapper是包装类,activity,application,service在初始化的时候会创建contextImpl实例实现context功能。所以activity,application,service本身来说就是context。broadcast与contentprovider用到的context是启动他们时传过来的。特殊一点就是,activity继承于ContextThemeWrapper,也是一个包装类,其内部包含了与主题(Theme)相关的接口,这里所说的主题就是指在AndroidManifest.xml中通过android:theme为Application元素或者Activity元素指定的主题。当然,只有Activity才需要主题,Service是不需要主题的,因为Service是没有界面的后台场景,所以Service直接继承于ContextWrapper,Application同理。
一句话总结:凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以,当然了,注意Context引用的持有,防止内存泄漏。(如何防止泄露简言之,引用者要比被引用的context死的早)
,有一篇关于ActivityThread与AppliactionTread的文章,很不错,不是吊书袋,看了之后了解更深。
Android M 5.0,关于ActivityThread和ApplicationThread的解析.
附上contextWrapper&contextThemeWrapper(增加theme相关功能)的部分相关代码(包装类,实现依靠mBases即contextImplement实现。contextImplement在 attachBaseContext() 方法里创建)
public class ContextWrapper extends Context { Context mBase; /** * 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; } /** * @return the base context as set by the constructor or setBaseContext */ public Context getBaseContext() { return mBase; } @Override public AssetManager getAssets() { return mBase.getAssets(); } @Override public Resources getResources() { return mBase.getResources(); } @Override public ContentResolver getContentResolver() { return mBase.getContentResolver(); } @Override public Looper getMainLooper() { return mBase.getMainLooper(); } @Override public Context getApplicationContext() { return mBase.getApplicationContext(); } @Override public String getPackageName() { return mBase.getPackageName(); } @Override public void startActivity(Intent intent) { mBase.startActivity(intent); } @Override public void sendBroadcast(Intent intent) { mBase.sendBroadcast(intent); } @Override public Intent registerReceiver( BroadcastReceiver receiver, IntentFilter filter) { return mBase.registerReceiver(receiver, filter); } @Override public void unregisterReceiver(BroadcastReceiver receiver) { mBase.unregisterReceiver(receiver); } @Override public ComponentName startService(Intent service) { return mBase.startService(service); } @Override public boolean stopService(Intent name) { return mBase.stopService(name); } @Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { return mBase.bindService(service, conn, flags); } @Override public void unbindService(ServiceConnection conn) { mBase.unbindService(conn); } @Override public Object getSystemService(String name) { return mBase.getSystemService(name); } ...... }
public class ContextThemeWrapper extends ContextWrapper { private int mThemeResource; private Resources.Theme mTheme; private LayoutInflater mInflater; private Configuration mOverrideConfiguration; private Resources mResources; public ContextThemeWrapper() { super(null); } public ContextThemeWrapper(Context base, @StyleRes int themeResId) { super(base); mThemeResource = themeResId; } public ContextThemeWrapper(Context base, Resources.Theme theme) { super(base); mTheme = theme; } @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); } /** * Call to set an "override configuration" on this context -- this is * a configuration that replies one or more values of the standard * configuration that is applied to the context. See * {@link Context#createConfigurationContext(Configuration)} for more * information. * * <p>This method can only be called once, and must be called before any * calls to {@link #getResources()} are made. */ public void applyOverrideConfiguration(Configuration overrideConfiguration) { if (mResources != null) { throw new IllegalStateException("getResources() has already been called"); } if (mOverrideConfiguration != null) { throw new IllegalStateException("Override configuration has already been set"); } mOverrideConfiguration = new Configuration(overrideConfiguration); } @Override public Resources getResources() { if (mResources != null) { return mResources; } if (mOverrideConfiguration == null) { mResources = super.getResources(); return mResources; } else { Context resc = createConfigurationContext(mOverrideConfiguration); mResources = resc.getResources(); return mResources; } } @Override public void setTheme(int resid) { if (mThemeResource != resid) { mThemeResource = resid; initializeTheme(); } } /** @hide */ @Override public int getThemeResId() { return mThemeResource; } @Override public Resources.Theme getTheme() { if (mTheme != null) { return mTheme; } mThemeResource = Resources.selectDefaultTheme(mThemeResource, getApplicationInfo().targetSdkVersion); initializeTheme(); return mTheme; } @Override public Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) { if (mInflater == null) { mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this); } return mInflater; } return getBaseContext().getSystemService(name); } /** * Called by {@link #setTheme} and {@link #getTheme} to apply a theme * resource to the current Theme object. Can override to change the * default (simple) behavior. This method will not be called in multiple * threads simultaneously. * * @param theme The Theme object being modified. * @param resid The theme style resource being applied to <var>theme</var>. * @param first Set to true if this is the first time a style is being * applied to <var>theme</var>. */ protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) { theme.applyStyle(resid, true); } private void initializeTheme() { final boolean first = mTheme == null; if (first) { mTheme = getResources().newTheme(); Resources.Theme theme = getBaseContext().getTheme(); if (theme != null) { mTheme.setTo(theme); } } onApplyThemeResource(mTheme, mThemeResource, first); } }