【android】分析activity的context、应用程序入口及Context.openOrCreateDatabase

来源:互联网 发布:手机移动网络开关 编辑:程序博客网 时间:2024/05/16 05:15
Context.openOrCreateDatabase与SQLiteDatabase.openOrCreateDatabase这两者没有什么区别,其本质都是调用了SQLiteDatabase.openDatabase方法来创建数据库:
[java] view plaincopyprint?
  1. public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags, DatabaseErrorHandler errorHandler) {  
  2.     SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler);  
  3.     db.open();  
  4.     return db;  
  5. }  

很多童鞋在追踪API源码的时候都会发现Activity类下的openOrCreateDatabase方法会指向ContextWrapper类下的openOrCreateDatabase方法:

[java] view plaincopyprint?
  1. @Override  
  2. public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {  
  3.     return mBase.openOrCreateDatabase(name, mode, factory);  
  4. }  
但是进一步追踪发现直接就去了Context.openOrCreateDatabase方法中了:

[java] view plaincopyprint?
  1. 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成员变量,其被赋值的地方有两处:

第一处:构造函数

[java] view plaincopyprint?
  1. public ContextThemeWrapper(Context base, int themeres) {  
  2.     super(base);  
  3.     mBase = base;  
  4.     mThemeResource = themeres;  
  5. }  
第二处:attachBaseContext方法

[java] view plaincopyprint?
  1. @Override  
  2. protected void attachBaseContext(Context newBase) {  
  3.     super.attachBaseContext(newBase);  
  4.     mBase = newBase;  
  5. }  
在Activity类中并没有调用父类ContextThemeWrapper的相关构造方法,因此我们先不管,但是在Activity.attach方法中调用了ContextThemeWrapper.attachBaseContext并传入了一个Context对象:

[java] view plaincopyprint?
  1. 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) {  
  2.     attachBaseContext(context);  
  3.     // 省去无关代码……………………  
  4. }  
那么attach方法又是在哪儿被调用的呢?传入attach方法的Context引用又是什么玩意呢?这里我们先留一个疑问!Mark,合影留念,茄子!

我们知道一个Android应用会有一个Activity作为程序启动时显示的主界面,而这个Activity我们会在AndroidManifest.xml文件中通过intent-filter来定义:

[html] view plaincopyprint?
  1. <activity  
  2.     android:name="com.aigestudio.MainActivity"  
  3.     android:label="@string/app_name" >  
  4.     <intent-filter>  
  5.         <action android:name="android.intent.action.MAIN" />  
  6.   
  7.         <category android:name="android.intent.category.LAUNCHER" />  
  8.     </intent-filter>  
  9. </activity>  
当该Activity启动后则会依次去走其生命周期方法onCreate----->onStart----->onResume----->等等,对于一些刚接触Android的童鞋来说,会认为MAIN定义的Activity的onCreate方法就是应用的入口,因为几乎我们所接触的所有东西都会从这里开始(当然静态代码块等其他的奇葩在这就不多争论了),是不是这样的呢?事实上,一个Android应用的真正入口应该是在ActivityThread(frameworks\base\core\java\android\app\ActivityThread.java),在该类中的Main方法里,其对Activity做了大量的初始化工作:
[java] view plaincopyprint?
  1. public final class ActivityThread {  
  2.     // 省略无数代码……………………  
  3.     public static void main(String[] args) {  
  4.         SamplingProfilerIntegration.start();  
  5.   
  6.         CloseGuard.setEnabled(false);  
  7.   
  8.         Environment.initForCurrentUser();  
  9.   
  10.         EventLogger.setReporter(new EventLoggingReporter());  
  11.   
  12.         Security.addProvider(new AndroidKeyStoreProvider());  
  13.   
  14.         Process.setArgV0("<pre-initialized>");  
  15.   
  16.         Looper.prepareMainLooper();  
  17.   
  18.         <strong>ActivityThread thread = new ActivityThread();  
  19.         thread.attach(false);  
  20.   
  21.         if (sMainThreadHandler == null) {  
  22.             sMainThreadHandler = thread.getHandler();  
  23.         }</strong>  
  24.   
  25.         AsyncTask.init();  
  26.   
  27.         if (false) {  
  28.             Looper.myLooper().setMessageLogging(new  
  29.                     LogPrinter(Log.DEBUG, "ActivityThread"));  
  30.         }  
  31.   
  32.         Looper.loop();  
  33.   
  34.         throw new RuntimeException("Main thread loop unexpectedly exited");  
  35.     }  
  36. }  
看到这个方法是不是有些似曾相似的感脚?我想即便是第一天学Java的童鞋都不会陌生。我们主要来看看这个方法中的一小部分:
[java] view plaincopyprint?
  1. ActivityThread thread = new ActivityThread();  
  2. // 省略一行代码……………………  
  3.   
  4. if (sMainThreadHandler == null) {  
  5.     sMainThreadHandler = thread.getHandler();  
  6. }  
这里实例化了本类获得了一个ActivityThread对象,sMainThreadHandler成员变量初始值为null:
[java] view plaincopyprint?
  1. static Handler sMainThreadHandler;  
也就是说每当ActivityThread类在被卸载后重新加载时都会执行
[java] view plaincopyprint?
  1. sMainThreadHandler = thread.getHandler();  
这条语句。ActivityThread类的getHandler()方法呢,返回的是内部类H的实例:
[java] view plaincopyprint?
  1. final Handler getHandler() {  
  2.     return mH;  
  3. }  
mH为成员变量并在类初始化时被赋值:
[java] view plaincopyprint?
  1. final H mH = new H();  
H类是Handler类的扩展类,作用很简单,就是处理ApplicationThread发送到消息队列的消息,而ApplicationThread则通过Binder与AMS进行通信并将其调用通过H类的实例对象将消息发送至消息队列,这一过程比较复杂与本文的关系不大这里就先不详解了,有空写篇关于Activity运行机制的文章再剖析,这里我们直接看H类中启动Activity的消息处理:
[java] view plaincopyprint?
  1. private class H extends Handler {  
  2.     // 省去大量代码……………………  
  3.     public void handleMessage(Message msg) {  
  4.         if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));  
  5.         switch (msg.what) {  
  6.             case LAUNCH_ACTIVITY: {  
  7.                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");  
  8.                 ActivityClientRecord r = (ActivityClientRecord)msg.obj;  
  9.   
  10.                 r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);  
  11.                 handleLaunchActivity(r, null);  
  12.                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);  
  13.             } break;  
  14.             // 省去大量代码……………………  
  15.         }  
  16.         // 省去一行代码……………………  
  17.     }  
  18.     // 省去大量代码……………………  
  19. }  
对我们来说这段消息处理的重点其实就是handleLaunchActivity(r, null)方法,该方法用来处理Activity启动的相关工作,具体实现如下:
[java] view plaincopyprint?
  1. private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {  
  2.     // 省去一些代码……………………  
  3.     Activity a = performLaunchActivity(r, customIntent);  
  4.   
  5.     // 省去一群代码……………………  
  6. }  
同样,对于本文我们也不需要关注其他的代码,重点就一行:Activity a = performLaunchActivity(r, customIntent);在performLaunchActivity方法中,有大量有关Activity的赋值和初始化操作并创建Activity的实例返回:
[java] view plaincopyprint?
  1. private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {  
  2.   
  3.     ActivityInfo aInfo = r.activityInfo;  
  4.     if (r.packageInfo == null) {  
  5.         r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE);  
  6.     }  
  7.   
  8.     ComponentName component = r.intent.getComponent();  
  9.     if (component == null) {  
  10.         component = r.intent.resolveActivity(mInitialApplication.getPackageManager());  
  11.         r.intent.setComponent(component);  
  12.     }  
  13.   
  14.     if (r.activityInfo.targetActivity != null) {  
  15.         component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity);  
  16.     }  
  17.   
  18.     Activity activity = null;  
  19.     try {  
  20.         java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  
  21.         activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);  
  22.         StrictMode.incrementExpectedActivityCount(activity.getClass());  
  23.         r.intent.setExtrasClassLoader(cl);  
  24.         if (r.state != null) {  
  25.             r.state.setClassLoader(cl);  
  26.         }  
  27.     } catch (Exception e) {  
  28.         if (!mInstrumentation.onException(activity, e)) {  
  29.             throw new RuntimeException("Unable to instantiate activity " + component + ": " + e.toString(), e);  
  30.         }  
  31.     }  
  32.   
  33.     try {  
  34.         Application app = r.packageInfo.makeApplication(false, mInstrumentation);  
  35.   
  36.         if (localLOGV)  
  37.             Slog.v(TAG, "Performing launch of " + r);  
  38.         if (localLOGV)  
  39.             Slog.v(TAG, r + ": app=" + app + ", appName=" + app.getPackageName() + ", pkg=" + r.packageInfo.getPackageName() + ", comp=" + r.intent.getComponent().toShortString() + ", dir=" + r.packageInfo.getAppDir());  
  40.   
  41.         if (activity != null) {  
  42.             Context appContext = createBaseContextForActivity(r, activity);  
  43.             CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());  
  44.             Configuration config = new Configuration(mCompatConfiguration);  
  45.             if (DEBUG_CONFIGURATION)  
  46.                 Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config);  
  47.             activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config);  
  48.   
  49.             if (customIntent != null) {  
  50.                 activity.mIntent = customIntent;  
  51.             }  
  52.             r.lastNonConfigurationInstances = null;  
  53.             activity.mStartedActivity = false;  
  54.             int theme = r.activityInfo.getThemeResource();  
  55.             if (theme != 0) {  
  56.                 activity.setTheme(theme);  
  57.             }  
  58.   
  59.             activity.mCalled = false;  
  60.             mInstrumentation.callActivityOnCreate(activity, r.state);  
  61.             if (!activity.mCalled) {  
  62.                 throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onCreate()");  
  63.             }  
  64.             r.activity = activity;  
  65.             r.stopped = true;  
  66.             if (!r.activity.mFinished) {  
  67.                 activity.performStart();  
  68.                 r.stopped = false;  
  69.             }  
  70.             if (!r.activity.mFinished) {  
  71.                 if (r.state != null) {  
  72.                     mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);  
  73.                 }  
  74.             }  
  75.             if (!r.activity.mFinished) {  
  76.                 activity.mCalled = false;  
  77.                 mInstrumentation.callActivityOnPostCreate(activity, r.state);  
  78.                 if (!activity.mCalled) {  
  79.                     throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPostCreate()");  
  80.                 }  
  81.             }  
  82.         }  
  83.         r.paused = true;  
  84.   
  85.         mActivities.put(r.token, r);  
  86.   
  87.     } catch (SuperNotCalledException e) {  
  88.         throw e;  
  89.   
  90.     } catch (Exception e) {  
  91.         if (!mInstrumentation.onException(activity, e)) {  
  92.             throw new RuntimeException("Unable to start activity " + component + ": " + e.toString(), e);  
  93.         }  
  94.     }  
  95.   
  96.     return activity;  
  97. }  
可以看到该方法有大量的赋值和初始化操作,什么ActivityInfo啊、ComponentName啊、Application啊、Configuration啊等等等等……………………当然还有我们的Activity的初始化:
[java] view plaincopyprint?
  1. activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);  
这里只是给大家提一下,我们的重点不在Activity我就不看这个方法了。重中之重呢就是其中Context的初始化和参数的传递:
[java] view plaincopyprint?
  1. Context appContext = createBaseContextForActivity(r, activity);  
  2. // 省去若干代码  
  3. 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方法看看呗~
[java] view plaincopyprint?
  1. private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {  
  2.     ContextImpl appContext = new ContextImpl();  
  3.     appContext.init(r.packageInfo, r.token, this);  
  4.     appContext.setOuterContext(activity);  
  5.   
  6.     Context baseContext = appContext;  
  7.     // 省略一段代码……………………  
  8.     return baseContext;  
  9. }  
索谍撕呢!原来传入attach方法的Context是ContextImpl(frameworks\base\core\java\android\app\ContextImpl.java)的一个实例!那ContextImpl当然也就是个Context的扩展类啦~哈哈哈哈,那我们看看能不能在其中找到openOrCreateDatabase的实现呢?答案是肯定的!:
[java] view plaincopyprint?
  1. @Override  
  2. public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) {  
  3.     File f = validateFilePath(name, true);  
  4.     int flags = SQLiteDatabase.CREATE_IF_NECESSARY;  
  5.     if ((mode & MODE_ENABLE_WRITE_AHEAD_LOGGING) != 0) {  
  6.         flags |= SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING;  
  7.     }  
  8.     SQLiteDatabase db = SQLiteDatabase.openDatabase(f.getPath(), factory, flags, errorHandler);  
  9.     setFilePermissionsFromMode(f.getPath(), mode, 0);  
  10.     return db;  
  11. }  
从上面的代码可以看到,其最终还是调用了SQLiteDatabase.openDatabase方法来创建数据库,而从Activity传入ContextThemeWrapper真正的Context则是Context的扩展类ContextImpl。

关于ContextImpl的内容很丰富,其内部代码就有两千行之巨,但是它依然是个轻量级的类,因为其大多数操作都是直接调用PackageInfo的方法来进行的,有机会可以对其再做更深的探讨,这篇文章呢就到此为止!虽说篇幅很长问题其实很简单,但是追求真理的道路我们不能停啊~同时……药不能停……Fuck!






转自http://blog.csdn.net/aigestudio/article/details/39029085
0 0
原创粉丝点击