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

Context.openOrCreateDatabase与SQLiteDatabase.openOrCreateDatabase这两者没有什么区别,其本质都是调用了SQLiteDatabase.openDatabase方法 来创建数据库:
[java]  view plain copy print ?
  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 plain copy print ?
  1. @Override  
  2. public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {  
  3.     return mBase.openOrCreateDatabase(name, mode, factory);  
  4. }  
但是进一步追踪发现直接就去了Context.openOrCreateDatabase方法中了:

[java]  view plain copy print ?
  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 plain copy print ?
  1. public ContextThemeWrapper(Context base, int themeres) {  
  2.     super(base);  
  3.     mBase = base;  
  4.     mThemeResource = themeres;  
  5. }  
第二处:attachBaseContext方法

[java]  view plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  1. ActivityThread thread = new ActivityThread();  
  2. // 省略一行代码……………………  
  3.   
  4. if (sMainThreadHandler == null) {  
  5.     sMainThreadHandler = thread.getHandler();  
  6. }  
这里实例化了本类获得了一个ActivityThread对象,sMainThreadHandler成员变量初始值为null:
[java]  view plain copy print ?
  1. static Handler sMainThreadHandler;  
也就是说每当ActivityThread类在被卸载后重新加载时都会执行
[java]  view plain copy print ?
  1. sMainThreadHandler = thread.getHandler();  
这条语句。ActivityThread类的getHandler()方法呢,返回的是内部类H的实例:
[java]  view plain copy print ?
  1. final Handler getHandler() {  
  2.     return mH;  
  3. }  
mH为成员变量并在类初始化时被赋值:
[java]  view plain copy print ?
  1. final H mH = new H();  
H类是Handler类的扩展类,作用很简单,就是处理ApplicationThread发送到消息队列的消息,而ApplicationThread则通过Binder与AMS进行通信并将其调用通过H类的实例对象将消息发送至消息队列,这一过程比较复杂与本文的关系不大这里就先不详解了,有空写篇关于Activity运行机制的文章再剖析,这里我们直接看H类中启动Activity的消息处理:
[java]  view plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  1. activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);  
这里只是给大家提一下,我们的重点不在Activity我就不看这个方法了。重中之重呢就是其中Context的初始化和参数的传递:
[java]  view plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  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
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值