咋看标题好像我在暗示两者会有一定的区别,其实我只是卖了个关子吸引下大家眼球,这两者没有什么区别,其本质都是调用了SQLiteDatabase.openDatabase方法来创建数据库:
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags, DatabaseErrorHandler errorHandler) { SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler); db.open(); return db; }
很多童鞋在追踪API源码的时候都会发现Activity类下的openOrCreateDatabase方法会指向ContextWrapper类下的openOrCreateDatabase方法:
@Override public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) { return mBase.openOrCreateDatabase(name, mode, factory); }
但是进一步追踪发现直接就去了Context.openOrCreateDatabase方法中了:
public abstract SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory);
没办法看到其实现过程……这里的原因有二:其一是因为Android确实没在API Source中提供该部分的有关源码;其二是因为我们并没有搞清楚ContextWrapper在构造函数中传入的Context引用究竟是什么。
大家知道Context作为Android的上下文环境引用抽象类对我们来说既熟悉又陌生,熟悉在于我们经常会使用到它,Android呢也有很多它的扩展类,陌生在于我们不知道本质是什么或者说其到底是个什么东西?关于Context的相关知识大家可以百度谷歌下,这方面的相关文档很多,在这里就不作过多介绍了,阅读本文你不需要知道过多的Context知识。
为了搞清楚ContextWrapper在构造函数中传入的Context引用我们回到Activity类中,Activity是ContextThemeWrapper扩展类,而ContextThemeWrapper类又扩展至ContextWrapper,在ContextThemeWrapper类中同样有一个名为mBase的Context成员变量,其被赋值的地方有两处:
第一处:构造函数
public ContextThemeWrapper(Context base, int themeres) { super(base); mBase = base; mThemeResource = themeres; }
第二处:attachBaseContext方法
@Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); mBase = newBase; }
在Activity类中并没有调用父类ContextThemeWrapper的相关构造方法,因此我们先不管,但是在Activity.attach方法中调用了ContextThemeWrapper.attachBaseContext并传入了一个Context对象:
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) { attachBaseContext(context); // 省去无关代码…………………… }
那么attach方法又是在哪儿被调用的呢?传入attach方法的Context引用又是什么玩意呢?这里我们先留一个疑问!Mark,合影留念,茄子!
我们知道一个Android应用会有一个Activity作为程序启动时显示的主界面,而这个Activity我们会在AndroidManifest.xml文件中通过intent-filter来定义:
<activity android:name="com.aigestudio.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
当该Activity启动后则会依次去走其生命周期方法onCreate----->onStart----->onResume----->等等,对于一些刚接触Android的童鞋来说,会认为MAIN定义的Activity的onCreate方法就是应用的入口,因为几乎我们所接触的所有东西都会从这里开始(当然静态代码块等其他的奇葩在这就不多争论了),是不是这样的呢?事实上,一个Android应用的真正入口应该是在ActivityThread(frameworks\base\core\java\android\app\ActivityThread.java),在该类中的Main方法里,其对Activity做了大量的初始化工作:
public final class ActivityThread { // 省略无数代码…………………… public static void main(String[] args) { SamplingProfilerIntegration.start(); CloseGuard.setEnabled(false); Environment.initForCurrentUser(); EventLogger.setReporter(new EventLoggingReporter()); Security.addProvider(new AndroidKeyStoreProvider()); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); <strong>ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); }</strong> AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } }
看到这个方法是不是有些似曾相似的感脚?我想即便是第一天学Java的童鞋都不会陌生。我们主要来看看这个方法中的一小部分:
ActivityThread thread = new ActivityThread(); // 省略一行代码…………………… if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); }
这里实例化了本类获得了一个ActivityThread对象,sMainThreadHandler成员变量初始值为null:
static Handler sMainThreadHandler;
也就是说每当ActivityThread类在被卸载后重新加载时都会执行
sMainThreadHandler = thread.getHandler();
这条语句。ActivityThread类的getHandler()方法呢,返回的是内部类H的实例:
final Handler getHandler() { return mH; }
mH为成员变量并在类初始化时被赋值:
final H mH = new H();
H类是Handler类的扩展类,作用很简单,就是处理ApplicationThread发送到消息队列的消息,而ApplicationThread则通过Binder与AMS进行通信并将其调用通过H类的实例对象将消息发送至消息队列,这一过程比较复杂与本文的关系不大这里就先不详解了,有空写篇关于Activity运行机制的文章再剖析,这里我们直接看H类中启动Activity的消息处理:
private class H extends Handler { // 省去大量代码…………………… public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { case LAUNCH_ACTIVITY: { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); ActivityClientRecord r = (ActivityClientRecord)msg.obj; r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; // 省去大量代码…………………… } // 省去一行代码…………………… } // 省去大量代码…………………… }
对我们来说这段消息处理的重点其实就是handleLaunchActivity(r, null)方法,该方法用来处理Activity启动的相关工作,具体实现如下:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { // 省去一些代码…………………… Activity a = performLaunchActivity(r, customIntent); // 省去一群代码…………………… }
同样,对于本文我们也不需要关注其他的代码,重点就一行:Activity a = performLaunchActivity(r, customIntent);在performLaunchActivity方法中,有大量有关Activity的赋值和初始化操作并创建Activity的实例返回:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity(mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity != null) { component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } 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); 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); } } 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()); 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); if (customIntent != null) { activity.mIntent = customIntent; } r.lastNonConfigurationInstances = null; activity.mStartedActivity = false; int theme = r.activityInfo.getThemeResource(); if (theme != 0) { activity.setTheme(theme); } activity.mCalled = false; 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; } if (!r.activity.mFinished) { if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } if (!r.activity.mFinished) { activity.mCalled = false; 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; 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; }
可以看到该方法有大量的赋值和初始化操作,什么ActivityInfo啊、ComponentName啊、Application啊、Configuration啊等等等等……………………当然还有我们的Activity的初始化:
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
这里只是给大家提一下,我们的重点不在Activity我就不看这个方法了。重中之重呢就是其中Context的初始化和参数的传递:
Context appContext = createBaseContextForActivity(r, activity); // 省去若干代码 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config);
注意到木有?这里再初始化了一个Context实例对象后直接将其引用传给了activity的attach方法!原来attach方法是在这里被调用并传入的Context!那么这个Context是什么呢?进去createBaseContextForActivity方法看看呗~
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) { ContextImpl appContext = new ContextImpl(); appContext.init(r.packageInfo, r.token, this); appContext.setOuterContext(activity); Context baseContext = appContext; // 省略一段代码…………………… return baseContext; }
索谍撕呢!原来传入attach方法的Context是ContextImpl(frameworks\base\core\java\android\app\ContextImpl.java)的一个实例!那ContextImpl当然也就是个Context的扩展类啦~哈哈哈哈,那我们看看能不能在其中找到openOrCreateDatabase的实现呢?答案是肯定的!:
@Override public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) { File f = validateFilePath(name, true); int flags = SQLiteDatabase.CREATE_IF_NECESSARY; if ((mode & MODE_ENABLE_WRITE_AHEAD_LOGGING) != 0) { flags |= SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING; } SQLiteDatabase db = SQLiteDatabase.openDatabase(f.getPath(), factory, flags, errorHandler); setFilePermissionsFromMode(f.getPath(), mode, 0); return db; }
从上面的代码可以看到,其最终还是调用了SQLiteDatabase.openDatabase方法来创建数据库,而从Activity传入ContextThemeWrapper真正的Context则是Context的扩展类ContextImpl。
关于ContextImpl的内容很丰富,其内部代码就有两千行之巨,但是它依然是个轻量级的类,因为其大多数操作都是直接调用PackageInfo的方法来进行的,有机会可以对其再做更深的探讨,这篇文章呢就到此为止!虽说篇幅很长问题其实很简单,但是追求真理的道路我们不能停啊~同时……药不能停……Fuck!