对于Context的一些理解

本文深入解析Android中的Context,包括Context的用途、不同类型的Context(如ApplicationContext、ActivityContext)及其应用场景。重点讨论了ContextImpl、ContextWrapper和ContextThemeWrapper的层级关系。还介绍了Context在启动Activity、设置主题以及UI交互中的注意事项,强调了不当使用可能导致的内存泄漏问题,并给出了避免内存泄漏的建议。同时,提到了getApplication()和getApplicationContext()的区别以及获取Context的常见方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关系图

context含义有语境,上下文,背景,环境等等。 Context是维持Android程序中各组件能够正常工作的一个核心功能类。

Context官方注释

Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.

有关应用程序环境的全局信息的接口。

这是一个抽象类,其实现由Android系统提供。(ContextImpl)

它允许访问特定于应以及调用应用程序级操作,例如启动活动、广播和接收意图等。

ContextWrapper

Proxying implementation of Context that simply delegates all of its calls to another Context. Can be subclassed to modify behavior
without changing the original Context.

Context 的代理实现,它只是将其所有调用委托给另一个 Context。可以在不改变原始上下文的情况下进行子类化以修改行为。

ContextImpl

Common implementation of Context API, which provides the base context object for Activity and other application components.

Context API 的通用实现,它为 Activity 和其他应用程序组件提供基础上下文对象。

ContextThemeWrapper

A context wrapper that allows you to modify or replace the theme of the wrapped context.

一个上下文包装器,允许您修改或替换包装的上下文的主题。

以上都是源码中的注释

对这个图的解释:

Context是一个抽象类,而ContextImpl是一个Context的实现类,用来作为ContextWrapper中的Context实例引用,由ContextImpl来实现Context中的抽象方法。ContextWrapper就是一个包装类,里面包含一个Context引用,调用其中的方法都会被转向Context实例,如同注释所写的那样,ContextThemeWrapper内部包含了与主题(Theme)相关的接口,这里所说的主题就是指在AndroidManifest.xml中通过android:theme为Application元素或者Activity元素指定的主题。当然,只有Activity才需要主题,Service是不需要主题的,因为Service是没有界面的后台场景,所以Service直接继承于ContextWrapper,Application同理。

源码:


ContextWrapper中的一个方法attachBaseContext

//源码
protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }
    mBase = base;
}

mBase是一个ContextWrapper中的Context引用,用来引用一个Context实例

在这里插入图片描述
可以看到源码中,ContextWrapper的方法调用中都含有mBase的引用,就相当于委托给mBase这个Context实例来调用方法


在这里插入图片描述

在ContextThemeWrapper中很明显可以看到有一些关于Theme的方法

Context作用域

在这里插入图片描述

1:如果我们用ApplicationContext去启动一个LaunchMode为standard的Activity的时候会报错android.util.AndroidRuntimeException: Calling startActivity from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?这是因为非Activity类型的Context并没有所谓的任务栈,所以待启动的Activity就找不到栈了。解决这个问题的方法就是为待启动的Activity指定FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候就为它创建一个新的任务栈,而此时Activity是以singleTask模式启动的。所有这种用Application启动Activity的方式不推荐使用,Service同Application。
2:在Application和Service中去layout inflate也是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。所以这种方式也不推荐使用。
一句话总结:凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以,当然了,注意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()

两者获取的都是同一个对象,都是application实例,application本身又是一个Context对象。getApplication()方法的语义性非常强,一看就知道是用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在绝大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法了。

Context引起的内存泄露

Context并不能随便乱用,用的不好有可能会引起内存泄露的问题,一般Context造成的内存泄漏,几乎都是当Context销毁的时候,却因为被引用导致销毁失败,而Application的Context对象可以理解为随着进程存在的

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


部分内容引用自:
作者:尹star
链接:https://www.jianshu.com/p/94e0f9ab3f1d
来源:简书

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值