你真的理解 Android 中的 Context 么?

简介:

概述

在使用getContext方法的时候有没有想过,在不同的场景下,取到的Context到底有什么不同,View,Fragment,Activity和Application的getContext又究竟是怎么样?

下面来分析一下。

获取Context

DecorView

DecorView的Context是Application Context。

ActivityThread.addView -> PhoneWindow.generateDecor

ec8f4ca712ce202124b314868098f375c8da03b4

View

一般View是从LayoutInflater类中inflate生成的,查看inflate方法,会调用rinflate

e815c24fca5258b8b148dbbaf0dd4da67b38484b

发现是入参Context,在inflate方法内赋值,其实最后就是LayoutInflater.from的参数Context。

所以结论是普通View是LayoutInflater.from的参数Context。

但是对于xml这样的布局文件里面的View又是怎么样的呢?

看一下Activity.setContentView方法的调用过程是:

Activity.setContentView -> PhoneWindow.setContentView -> LayoutInflater.inflate方法,而这个LayoutInflater是在PhoneWindow的构造方法内创建的,回到Activity.attach方法,看到构造方法的参数是Activity的Context。

43ef77e92208881874e7cc64f44fa1fa8c104955

于是增加一个结论,在xml中解析的View的Context属于Activity。

可能有人问,那Fragment也是吗?看一下Fragment.onCreateView中参数有LayoutInflater,跟踪一下

Fragment.onCreateView <- Fragment.performCreateView -> FragmentManagerImpl.moveToState <- Fragment.performGetLayoutInflater <- Fragment.getLayoutInflater <- FragmentHostCallback.onGetLayoutInflater

结果是用了FramgentHostCallback构造方法的参数Context

ee1cf2c1a34fdc97d0eee777af12860aa06a7f7a

结论也是Activity的Context。

FragmentActivity

一般使用FragmentActivity.this和FragmentActivity.getContext方法取到Context,最终取到的都是Activity的Context,不再赘述。

Fragment

通过Fragment.getContext取到Context,结果是取到FragmentHostCallback.getContext也是Activity的Context。

Application

取到的是Application Context。

Applicaiton与Activity的区别

所以最终的目的是区分Application与Activity的Context有什么不同。所以看它们各自的实现,Application与Activity都继承于ContextWrapper,ContextWrapper就是包装了一下抽象类Context,在构造方法里传入Context对象,根本在于构建Application和Activity的地方。

追踪一下发现Context构建都在ContextImpl类内,Application对应createAppContext,而Activity则对应createActivityContext,都在ActivityThread中调用各自创建Context方法进行初始化。

cd8ea307efac1ecbd56a1304d9a526edb2c4630d

对比ContextImpl的构建,前三个参数都一致,Activity的Context多了activityToken和classLoder,其中activityToken对应ActivityRecord类,接着调用Context.setResource方法设置Activity的配置和逻辑显示相关的信息Display。

23360efb22821bdec9231c25350b1830355485f1

看一下这个熟悉的错误,这个是使用Application的Context启动Activity时报的错误,这个mSourceRecord就是AcitivityRecord对象,对于Application而言为null,所以需要指定New_Task这个标志。

两者之间更重要的一个区别是:生命周期。

对于Application的Context而言,在整个应用的生命周期内都不会改变;而对于不同的Activity,其Context有可能不同,例如添加一个Dialog必须附着在Activity上,所以使用Application就会报错。

72975c1f0ea41c5182d5023870d20cf854e2a032

总结

除了Application,DecorView和getApplicationContext方法会取到Application Context外,其他方法getContext都会取到Activity Context或者传入的Context。

一般来说,Application Context存在于整个应用的生命周期中,不会随场景变化而改变,所以对于打开不同的Activity,Activity Context可能存在不同,而且生命周期跟Activity的生命周期一致。


原文发布时间为:2018-11-22

本文作者:豆沙包67

本文来自云栖社区合作伙伴“安卓巴士Android开发者门户”,了解相关信息可以关注“安卓巴士Android开发者门户”。

相关文章
|
程序员 数据库 Android开发
面试问你Android中Context,你如何回答?
面试问你Android中Context,你如何回答?
103 0
|
Android开发
Android LayoutInflater.from(context).inflate()方法的作用
Android LayoutInflater.from(context).inflate()方法的作用
70 0
|
Android开发
Android 中实现上下文菜单(Context menu)详解
Android 中实现上下文菜单(Context menu)详解
100 0
|
XML Android开发 数据格式
Android 彩色上下文菜单 Context
Android 彩色上下文菜单 Context
|
API Android开发 对象存储
Android | 使用 ContentProvider 无侵入获取 Context
Android | 使用 ContentProvider 无侵入获取 Context
449 0
Android | 使用 ContentProvider 无侵入获取 Context
|
设计模式 Java Android开发
Android 复习笔记 —— 扒一扒 Context
Android 复习笔记 —— 扒一扒 Context
Android 复习笔记 —— 扒一扒 Context
|
Java Android开发 开发者
Android Context ContextWrapper ContextImpl Activity Service关系
Android Context ContextWrapper ContextImpl Activity Service关系
Android Context ContextWrapper ContextImpl Activity Service关系
|
Android开发
Android之Context 和 application context
Android之Context 和 application context
175 0
Android之Context 和 application context
|
Android开发
Android之Context和Activity互相转换
Android之Context和Activity互相转换
947 0
|
设计模式 安全 IDE
Context都没弄明白,还怎么做Android开发?
什么是 Context? 四大组件和 Context Application 和 Context 为什么 Application 的 Context 不可以创建 Dialog ?