Context详解

2,998 阅读4分钟

Activity mActivity =new Activity()?

Android应用模型是基于组件的应用设计模式,组件的运行要有一个完整的Android工程环境,在这个环境下,Activity、Service等系统组件才能够正常工作,而这些组件并不能采用普通的Java对象创建方式,new一下就能创建实例了,而是要有它们各自的上下文环境,也就是我们这里讨论的Context。可以这样讲,Context是维持Android程序中各组件能够正常工作的一个核心功能类。

Context的中文翻译为:语境; 上下文; 背景; 环境 在程序中,我们可以理解为当前对象在程序中所处的一个环境,一个与系统交互的过程。 Context在加载资源、启动Activity、获取系统服务、创建View等操作都要参与。

context关系图

Context类本身是一个纯abstract类,它有两个具体的实现子类:ContextImpl和ContextWrapper。

其中ContextWrapper类,如其名所言,这只是一个包装而已,ContextWrapper构造函数中必须包含一个真正的Context引用,同时ContextWrapper中提供了attachBaseContext()用于给ContextWrapper对象中指定真正的Context对象,调用ContextWrapper的方法都会被转向其所包含的真正的Context对象。

ContextThemeWrapper类,如其名所言,其内部包含了与主题(Theme)相关的接口,这里所说的主题就是指在AndroidManifest.xml中通过android:theme为Application元素或者Activity元素指定的主题。当然,只有Activity才需要主题,Service是不需要主题的,因为Service是没有界面的后台场景,所以Service直接继承于ContextWrapper,Application同理。

而ContextImpl类则真正实现了Context中的所有函数,应用程序中所调用的各种Context类的方法,其实现均来自于该类。一句话总结:Context的两个子类分工明确,其中ContextImpl是Context的具体实现类,ContextWrapper是Context的包装类。

Activity,Application,Service虽都继承自ContextWrapper(Activity继承自ContextWrapper的子类ContextThemeWrapper),但它们初始化的过程中都会创建ContextImpl对象,由ContextImpl实现Context中的方法。

作用域

一个Activity的启动必须要建立在另一个Activity的基础之上,Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog)

image.png

Application和Service所不推荐的两种使用情况

    1. 用ApplicationContext去启动一个LaunchMode为standard的Activity的时候会报AndroidRuntimeException,因为非Activity类型的Context并没有任务栈,所以待启动的Activity就找不到栈了,需要加FLAG_ACTIVITY_NEW_TASK标记位位,此时Activity启动模式变成singleTask。
    1. 在Application和Service中去layout inflate是合法的,但是会使用系统默认的主题样式,自定义样式可能不会被使用。

获取Context对象

通常我们想要获取Context对象,主要有以下四种方法

  • 1:View.getContext,返回当前View对象的Context对象,通常是当前正在展示的Activity对象。
  • 2:Activity.getApplicationContext,获取当前Activity所在的(应用)进程的Context对象,通常我们使用Context对象时,要优先考虑这个全局的进程Context。
  • 3:ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context,可以使用这个方法,这个方法在实际开发中使用并不多,也不建议使用。
  • 4:Activity.this 返回当前的Activity实例,如果是UI控件需要使用Activity作为Context对象,但是默认的Toast实际上使用ApplicationContext也可以。

getApplication()和getApplicationContext()

Acivity和Service类里成员变量Application,可以通过getApplication()拿到,也可以通过getApplicationContext()拿。BroadcastReceiver只能通过context的getApplicationContext()拿到。可以看出getApplication()和getApplication()作用域是不同的

正确使用Context,避免内存泄露

  • 1:当Application的Context能搞定的情况下,并且生命周期长的对象,优先使用Application的Context。
  • 2:不要让生命周期长于Activity的对象持有到Activity的引用。
  • 3:尽量不要在Activity中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用,可能导致内存泄漏,如果使用静态内部类,将外部实例引用作为弱引用持有。

参考地址:

www.jianshu.com/p/94e0f9ab3…

stay4it.com/course/25

blog.csdn.net/guolin_blog…

blog.csdn.net/yanbober/ar…