这儿边试官首要调查的是开发者是否了解Context的相关知识?

  1. Context是什么
  2. Context的结构
  3. Context的留意事项

问题正解:

一、Context是什么

Context 是 Android 顶用的十分常见的一种概念,常被翻译成上下文,这个概念在其他的技术中也有运用。Android 官方对它的解释,能够理解为运用程序环境中全局信息的接口,它整合了相当多体系级的服务,能够用来得到运用中的类、资源,以及能够进行运用程序级的调起操作,比如发动 Activity、Service等等,而且 Context 这个类是 笼统abstract 的,不含有具体的函数完结。

二、Context结构

Context 是维持 Android 程序中各组件能够正常工作的一个中心功用类。

Context 自身是一个笼统类,其首要完结类为 ContextImpl,还有直系子类两个:

  • ContextWrapper
  • ContextThemeWrapper

这两个子类是 Context 的署理类,它们继承联系如下:

从面试官角度分析:介绍一下Android中的Context?

ContextImpl类介绍

ContextImpl 是 Context API 的十分常见完结,它为 Activity 和其他运用程序组件供给根本上下文方针,说白了便是 ContextImpl 完结了笼统类的办法,咱们在运用 Context 的时分的办法便是它完结的。

ContextWrapper类介绍

ContextWrapper 类署理 Context 的完结,将其所有调用简单地署理给另一个 Context 方针(ContextImpl),能够被分类为修饰行为而不更改原始 Context 的类,其实就 Context 类的修饰类。真实的完结类是 ContextImpl,ContextWrapper 里边的办法履行也是履行 ContextImpl 里边的办法。

ContextThemeWrapper

便是一个带有主题的封装类,比 ContextWrapper 多了主题,它的一个直接子类便是 Activity。

经过Context的继承联系图结合咱们几个开发中比较常见的类,Activity、Service、Application,所以Context 一共有三种类型,分别是 Application、Activity 和Service,他们分别承担不同的责任,都归于 Context,而他们具有 Context 的功用则是由ContextImpl 类完结的。

三、Context的数量

其实依据上面的 Context 类型咱们就现已能够得出答案了。Context 一共有 Application、Activity 和 Service 三种类型方针,因而一个运用程序中Context 数量的计算公式就能够这样写:

Context数量 = Activity数量 + Service数量 + 1

上面的1代表着 Application 的数量,由于一个运用程序中能够有多个 Activity 和多个 Service,可是只能有一个 Application。

四、Context留意事项

Context 假如运用不恰当很容易引起内存走漏问题。

最简单的比如比如说运用了 Context 的过错的单例模式:

public class Singleton {
   private static Singleton instance;
   private Context mContext;
​
   private Singleton(Context context) {
     this.mContext = context;
   }
​
   public static Synchronized Singleton getInstance(Context context) {
     if (instance == null) {
       instance = new Singleton(context);
     }
     return instance;
   }
}

上述代码中,咱们使得了一个静态方针持有 Context 方针,而静态数据的生命一般是善于普通方针的,因而当 Context 被毁掉(例如假定这儿持有的是 Activity 的上下文方针,当 Activity 被毁掉的时分),由于 instance 依然持有 Context 的引证,导致 Context 尽管被毁掉了可是却无法被GC机制收回,由于形成内存走漏问题。

而一般由于Context所形成的内存泄漏,根本上都是 Context 现已被毁掉后,却由于被引证导致GC收回失败。可是 Application 的 Context 方针却会跟着当前进程而一直存在,所以运用 Context 是应当留意:

  • 当 Application 的 Context 能完结需要的情况下,而且生命周期长的方针,优先运用 Application 的 Context。
  • 不要让生命周期善于 Activity 的方针持有到 Activity 的引证。
  • 尽量不在 Activity 中运用非静态内部类,由于非静态内部类会隐式持有外部类实例的引证,假如运用静态内部类,将外部实例引证作为弱引证持有。
五、怎么正确回复以上面试题
  1. 面试官:Android 中有多少类型的 Context,它们有什么差异?

回答总共有 Activity 、Service、Application 这些 Context 。

共同点:它们都是 ContextWrapper 的派生类,而 ContextWrapper 的成员变量 mBase 能够用来寄存体系完结的 ContextImpl,这样咱们在履行如 Activity 的 Context 办法时,都是经过静态署理的方式最终履行到 ContextImpl 的办法。咱们调用 ContextWrapper 的 getBaseContext 办法就能得到 ContextImpl 的实例。

不同点:它们有各自不同的生命周期;在功用上,只要 Activity 显现界面,正由于如此,Activity 继承的是 ContextThemeWrapper 供给一些关于主题、界面显现的能力,间接继承了 ContextWrapper ;而 Applicaiton 、Service 都是直接继承 ContextWrapper ,所以咱们留意一点,凡是跟 UI 有关的,都应该用 Activity 作为 Context 来处理,否则要么会报错,要么 UI 会运用体系默认的主题。

  1. 面试官:一个APP运用里有几个 Context 呢?

Context 一共有 Application 、Activity 和 Service 三种类型,因而一个运用程序中 Context 数量的计算公式就能够这样写:

Context 数量 = Activity 数量 + Service 数量 + 1

上面的1代表着 Application 的数量,由于一个App中能够有多个Activity和多个 Service,可是只能有一个 Application。

  1. 面试官:Android 开发过程中,Context 有什么用?

Context 就等于 Application 的大管家,首要担任:

  • 四大组件的信息交互,包含发动 Activity、Broadcast、Service,获取 ContentResolver 等。
  • 获取体系/运用资源,包含 AssetManager、PackageManager、Resources、System Service 以及 color、string、drawable 等。
  • 文件,包含获取缓存文件夹、删去文件、SharedPreference 相关等。
  • 数据库(SQLite)相关,包含打开数据库、删去数据库、获取数据库途径等。

其它辅佐功用,比如装备 ComponentCallbacks,即监听装备信息改变、内存不足等事件的产生

  1. 面试官:ContextImpl 实例是什么时分生成的,在 Activity 的 onCreate 里能拿到这个实例吗?

能够。咱们开发的时分,常常会在 onCreate 里拿到 Application,假如用 getApplicationContext 取,最终调用的便是 ContextImpl 的 getApplicationContext 办法,假如调用的是 getApplication 办法,尽管没调用到 ContextImpl ,可是返回 Activity 的成员变量 mApplication 和 ContextImpl 的初始化机遇是相同的。 再说下它的原理,Activity 真实开端发动是从 ActivityThread.performLaunchActivity 开端的,这个办法做了这些事:

  • 经过 ClassLoader 去加载方针 Activity 的类,然后创立 方针。
  • 从 packageInfo 里获取 Application 方针。
  • 调用 createBaseContextForActivity 办法去创立 ContextImpl。
  • 调用 activity.attach ( contextImpl , application) 这个办法就把 Activity 和 Application 以及 ContextImpl 关联起来了,便是上面结论里说的机遇相同。
  • 最终调用 activity.onCreate 生命周期回调。

经过以上的分析,咱们知道了 Activity 是先创立类,再初始化 Context ,最终调用 onCreate , 然后得出问题的答案。不只 Activity 是这样, Application 、Service 里的 Context 初始化也都是这样的。

  1. 面试官:ContextImpl 、ContextWrapper、ContextThemeWrapper 有什么差异?
  • ContextWrapper、ContextThemeWrapper 都是 Context 的署理类,二者的差异在于 ContextThemeWrapper 有自己的 Theme 以及 Resource,而且 Resource 能够传入自己的装备初始化。
  • ContextImpl 是 Context 的首要完结类,Activity、Service 和 Application 的 Base Context 都是由它建立的,即 ContextWrapper 署理的便是 ContextImpl 方针自身。
  • ContextImpl 和 ContextThemeWrapper 的首要差异是, ContextThemeWrapper 有 Configuration 方针,Resource 能够依据这个方针来初始化。
  • Service 和 Application 运用同一个 Recource,和 Activity 运用的 Resource 不同。
  1. 面试官:Activity Context、Service Context、Application Context、Base Context 有什么差异?
  • Activity、Service 和 Application 的 Base Context 都是由 ContextImpl 创立的,且创立的都是 ContextImpl 方针,即它们都是 ContextImpl 的署理类 。
  • Service 和 Application 运用相同的Recource,和 Activity 运用的 Resource 不同。
  • getApplicationContext 返回的便是 Application 方针自身,一般情况下它对应的是运用自身的 Application 方针,但也或许是体系的某个 Application。
  1. 面试官:为什么不推荐运用 BaseContext?
  • 关于 Service 和 Application 来说,不推荐运用 Base Context,是忧虑用户修正了 Base Context 而导致呈现过错。
  • 关于 Activity 而言,除了忧虑用户的修正之外,Base Context 和 Activity 自身关于 Reource 以及 Theme 的相关行为是不同的(假如运用了 Configuration 的话),运用 Base Context 或许呈现无法预期的现象。
  1. 面试官:ContentProvider 里的 Context 是什么时分初始化的呢?

ContentProvider 不是 Context ,可是它有一个成员属性 mContext ,是经过结构函数传入的。那么这个问题就变成了,ContentProvider 什么时分创立。运用创立 Application 是经过履行 ActivityThread.handleBindApplication 办法,这个办法的相关流程有:

  • 创立 Application
  • 初始化 Application 的 Context
  • 履行 installContentProviders 并传入刚创立好的 Application 来创立 ContentProvider
  • 履行 Application.onCreate

得出结论,ContentProvider 的 Context 是在 Applicaiton 创立之后,可是 onCreate 办法调用之前初始化的。

  1. 面试官:BroadcastReceiver 里的 Context是哪来的?

播送接收器,分动态注册和静态注册。

  • 动态注册很简单,在调用 Context.registerReceiver 动态注册 BroadcastReceiver 时,会生成一个 ReceiverDispatcher 会持有这个 Context ,这样当有播送分发到它时,履行 onReceiver 办法就能够把 Context 传递过去了。当然,这也是为什么不用的时分要 unregisterReceiver 取消注册,否则这个 Context 就泄漏了哦。
  • 静态注册时,在分发的时分最终履行的是 ActivityThread.handleReceiver ,这个办法直接经过 ClassLoader 去创立一个 BroadcastReceiver 的方针,而传递给 onReceiver 办法的 Context 则是经过 context.getReceiverRestrictedContext() 生成的一个以 Application 为 mBase 的 ContextWrapper。留意这边的 Context 不是 Application 。

今天共享到此结束,对你有协助的话,点个赞再走呗,下期更精彩~

重视大众号:Android老皮
解锁 《Android十大板块文档》 ,让学习更靠近未来实战。已形成PDF版

内容如下

1.Android车载运用开发体系学习指南(附项目实战)
2.Android Framework学习指南,助力成为体系级开发高手
3.2023最新Android中高级面试题汇总+解析,离别零offer
4.企业级Android音视频开发学习路线+项目实战(附源码)
5.Android Jetpack从入门到通晓,构建高质量UI界面
6.Flutter技术解析与实战,跨平台首要之选
7.Kotlin从入门到实战,全方面提升架构基础
8.高级Android插件化与组件化(含实战教程和源码)
9.Android 功能优化实战+360全方面功能调优
10.Android零基础入门到通晓,高手进阶之路

敲代码不易,重视一下吧。ღ( ・ᴗ・` )