征服安卓面试官路漫漫:从源码深扒一下四大组件和Context( 三 )
注意 attach() 方法中的 setWindowManager() 方法中的 mToken 参数 , 这决定了 Application Context 无法创建和显示 Dialog。 后续会进行详细分析 。
再回头看看文章开头的问题 。
Log.e("context", "getApplication in Activity: " + getApplication().getClass().getName());Log.e("context", "getApplicationContext in Activity: " + getApplicationContext().getClass().getName());Log.e("context", "getBaseContext in Activity: " + getBaseContext().getClass().getName());
第一个 getApplication(), 看下源码就知道了:
public final Application getApplication() {return mApplication;}
getApplication() 返回的是当前的 Application 对象 。 开发者没有声明自己实现的 Application 的话 , 就是系统默认的 android.app.Application 。
第二个 getApplicationContext() , 它并不是 Activity 中的方法 , 而是 ContextWrapper 的 。 直接看源码:
@Overridepublic Context getApplicationContext() {return mBase.getApplicationContext();}
调用的是 ContextImpl.getApplicationContext()。
@Overridepublic Context getApplicationContext() {return (mPackageInfo != null) ?mPackageInfo.getApplication() : mMainThread.getApplication();}
所以返回的同样是 Application 对象 。
第三个 , getBaseContext(), 同样是 ContextWrapper 中的方法:
public Context getBaseContext() {return mBase;}
所以这里返回的是 ContextImpl 对象 。
最后的打印语句是:
E/context: getApplication in Activity: luyao.android.AppE/context: getApplicationContext in Activity: luyao.android.AppE/context: getBaseContext in Activity: android.app.ContextImpl
关于 Activity 就说这么多了 。 下面来看看 Service。
Service 和 ContextService 其实和 Activity 的整体流程基本一致 , 创建服务的主要逻辑在 ActivityThread.handleCreateService() 方法中 。 这里我就不贴源码了 , 简单叙述一下:
- 创建 LoadedApk 对象
- 反射创建 Service 对象
- 调用 ContextImpl.createAppCntext() 创建 ContextImpl 对象
- 创建 Application 对象
- 调用 service.attach() 进行绑定
- 回调 service 的 onCreate() 方法
public final void attach(Context context,ActivityThread thread, String className, IBinder token,Application application, Object activityManager) {attachBaseContext(context);......}
又看到了熟悉的 attachBaseContext() 方法 。Activity 和 Service 都是继承自 ContextWrapper 的 , 最后都是通过 attachBaseContext() 对 ContextImpl 类型的 mBase 赋值 。 而 ContentProvider 和 BroadcastReceiver 都没有继承 Context , 所以它们获取 Context 的方式会有一点不一样 。
ContentProvider 和 Context先来看 ContentProvider , 创建 Provider 的逻辑在 Activity.installProvider() 方法中:
private ContentProviderHolder installProvider(Context context,ContentProviderHolder holder, ProviderInfo info,boolean noisy, boolean noReleaseNeeded, boolean stable) {ContentProvider localProvider = null;IContentProvider provider;// 创建 LoadedApk 和 ContextImplc = context.createPackageContext(ai.packageName,Context.CONTEXT_INCLUDE_CODE);try {......// 创建 ContentProviderlocalProvider = packageInfo.getAppFactory().instantiateProvider(cl, info.name);provider = localProvider.getIContentProvider();......// 绑定 ContextlocalProvider.attachInfo(c, info);} catch (java.lang.Exception e) {......}......return retHolder;}
最后在 ContentProvider.attachInfo() 方法中进行了 ContextImpl 的赋值操作 。private void attachInfo(Context context, ProviderInfo info, boolean testing) {if (mContext == null) {// 给 mContext 赋值mContext = context;......// 回调 onCreate()ContentProvider.this.onCreate();}}
这样 ContentProvider 也能拿到 Context 对象了 。BroadcastReceiver 和 Context最后就是 BroadcastReceiver 了 , 对应 ActivityThread.handleReceiver()方法:
private void handleReceiver(ReceiverData data) {......// 创建 LoadedApk 对象LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);Application app;BroadcastReceiver receiver;ContextImpl context;try {// 创建 Application 对象app = packageInfo.makeApplication(false, mInstrumentation);// 创建 ContextImpl 对象context = (ContextImpl) app.getBaseContext();......// 创建 BroadcastReceiver 对象receiver = packageInfo.getAppFactory().instantiateReceiver(cl, data.info.name, data.intent);} catch (Exception e) {......}try {......// 回调 onReceive()receiver.onReceive(context.getReceiverRestrictedContext(),data.intent);} catch (Exception e) {......} finally {sCurrentBroadcastIntent.set(null);}......}
大多数步骤和 Activity 还是类似的 , 只是到最后回调 onReceive() 方法的时候 , 才会把 ContextImpl 对象传过去 。 注意 , 这里并不是直接返回原生的 ContextImpl 对象 , 而是调用 context.getReceiverRestrictedContext()返回一个 受限制 的 ReceiverRestrictedContext , 你无法使用这个 Context 对象启动 Service。
- 王文鉴|从工人到千亿掌门人,征服华为三星,只因他36年只坚持做一件事
- 手机|预算只有五千,买4G的iPhone11还是买国产5G安卓机?
- 华为|安兔兔10月安卓性能榜:华为Mate40 Pro第一 麒麟9000碾压骁龙865
- 重磅!高通骁龙888正式发布,安卓手机将大变
- 三年Java开发,刚从美团、京东、阿里面试归来,分享个人面经
- 华为|从工人到千亿掌门人,征服华为三星,只因他36年只坚持做一件事
- java面试题整理
- 面试官:问你一个,Spring事务是如何传播的?
- 安卓手机用户必看:谷歌公布2020年度最佳应用和游戏
- 程序员面试主要看哪些 该怎么准备面试内容