Context你真的了解吗?

本文详细解析了Android中Context的概念、原理及其使用场景,探讨了Context的获取方式、不同层级的作用域,以及不当使用可能导致的内存泄漏问题。

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

前言

Context是什么?

Context提供了关于应用环境全局信息的接口。它是一个抽象类,它的执行被android系统所提供。它允许获取以应用为特征的资源和类型,是一个统领一些资源(应用环境变量等)的上下文

Context原理图!

image

原理图分析:

Context是一个抽象类,Context有两个子类:ContextImpl和ContextWrapper,两个类的区别ContextImpl类是具体实现功能的类,而ContextWrapper只是用来进行一些包装等,但是会看到ContextThemeWrapper和Application还有Service都是继承了ContextWrapper,不是说ContextImpl是具体实现内容的类吗?因为那三个内容初始化过程中都会创建ContextImpl对象,由ContextImpl实现Context中的方法,看原理图中ContextWrapper指向ContextImpl的箭头就是这个意思。

Context的获取方式

  • View.getContext,返回当前View的Context对象,通常就是当前正在显示的Activity对象
  • Activity.this,返回当前Activity的实例,一般UI相关的使用这个作为Context对象(Toast有些特殊,可以直接使用ApplicationContext,因为Toast的Window是系统Window)
  • Activity.getApplicationContext()获取当前Activity所在应用进程的Context对象

    注意:这里还有个getApplication,getApplication和getApplicationContext有什么区别?
    getApplication和getApplicationContext获取的是同一个实例;getApplication方法的语义更强,但是只有在Activity或者Service中使用Application;但是如果在BroadcastReceiver等其它场景获取实例,只能借助getApplicationContext

  • ContextWrapper.getBaseContext()知道有这个获取方式就行

Context的使用场景

Context作用域ApplicationActivityService
show a dialogNoYESNo
strat an Activity不推荐YES不推荐
Layout Inflation不推荐YES不推荐
Start a ServiceYESYESYES
Send a BroadcastYESYESYES
Register Broadcast ReceiverYESYESYES
Load Resource ValuesYESYESYES

上面的表格时对整体Context使用场景的一个汇总,在这里只对前三条特殊的进行说明:
- show a dialog

Dialog时不允许凭空出现,必须有对应Activity,才能在Window上显示(有视图的地方就有),所以需要使用Activity的Context,Application和Service不能显示Dialog。但是在Activity中,如果非要使用Application的context来开启dialog一定不可以吗?不是的,需要改变dialog的一个属性,修改为在系统级别Window显示,具体请看博客:https://blog.youkuaiyun.com/xgangzai/article/details/81390630中的Dialog的Window创建过程
- start an Activity

启动一个Activity,用Application的Context会报错,这是因为Application的context并没有所谓的任务栈。新启动的Activity找不到任务栈无法入栈。但是这种办法也可以解决,为待启动的Activity指定一个flag标记位,这样启动的时候会为它创建一个新的任务栈,这种Activity是以singleTask方式启动。(不推荐)
- Layout Inflation

使用Application中的context或者service中的context,自定义的主题样式不会被使用。

总结:一般和UI相关的都使用Activity的context。

Context相关问题

面试中可能会问到一个应用程序中正常情况下会包含多少个Context?

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

其中1指的是Application的数量

四大组件中BroadcastReceiver,ContentProvide并不是Context的子类,在使用的时候都是通过其它地方传递过去。

Activity为什么不能直接new出来?

在刚接到项目代码时候,代码中竟然出现了在变量声明的时候,直接new出来一个Activity,当时真的很无语。那么说一下Activity为什么不能直接new出一个对象呢?

Android程序和java程序不一样,java中创建一个类,写一个Main方法就可以跑了,Android应用时基于组件的应用设计模式,组件的运行还必须有一个完整的工程环境,环境我们在上面说了也就是Context,只有在这种上下文环境(Context)下,Activity,Service,BroadcastReceiver等系统组件才能正常工作,所以这些组件直接采用java普通的对象创建形式new出来时不可行的。

Context造成的内存泄漏?
错误的单例模式

传进来Activity的context之后一直保存Activity传递进来的context引用,即使Activity被销毁掉也不会回收context引用。造成内存泄漏,(简单的说,Activity的context往出传的时候多想想,尽量不要)

代码如下:

public class Singleton(){
    private static Single instance;
    private Context context;

    private Singleton(Context context){
        this.context=context;
    }

    public static Singleton getInstance(Context context){
        if(instance==null){
            instance=new Singleton(context.getApplication());
        }
        return instance;
    }
}

总结,如何正确使用Context

  • Application的Context能解决的情况下,优先使用Application的context
  • 不要让生命周期长于Activity的对象持有到Activity的引用,不然会造成内存泄漏
  • 静态内部类使用的时候要注意,进了不要再Activity中使用,因为非静态内部类会隐式持有外部实例的引用,如果使用静态内部类,将外部实例引用为弱引用持有(联想ListView使用的时候Adapter的创建)

android内存泄漏相关内没进行详细总结,可参考文章学习:
https://blog.youkuaiyun.com/u010198148/article/details/51649852

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值