掌握Android Context刻不容缓

本文介绍了Android中的Context概念及其重要性,详细解析了Application、Activity/Service、BroadcastReceiver和ContentProvider四种类型的Context,强调了错误使用Context可能导致的内存泄漏问题,并提供了解决方案。同时,对比了不同Context在功能上的差异,帮助开发者更好地理解和运用。
摘要由CSDN通过智能技术生成

引言

Context应该是每个Android入门开发者第一个接触到的概念,它代表当前上下文环境,可以用来实现很多功能的调用。

我们最常见的有这些

//获取资源管理器对象,进而可以访问到string,color等资源
Resources resources = context.getResources();
//启动指定的Activity
context.startActivity(new Intent(this,MainActivity.class));
//获取各种系统服务
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
//获取系统文件目录
File internalDir = context.getCacheDir();
File internalDir = context.getExternalCacheDir();

可见,正确理解context很重要。在实际开发中我们会遇到各种各样的context,但是你要知道,每一个context都是有自己的含义的,并不是都相同的哦。这点你搞错了,那么开发也就进行不下去了。

Context种类

我们一般按照Context依托的组件和用途不同来进行分类:

  • Application:Android应用中的默认单例类,在Activity或者service中可以通过getApplication()获取到这个单例。通过context.getApplicationContext()可以获取到应用全局唯一Context实例。
  • Activity/Service :这两个类都是ContextWrapper的子类,在这两个类中可以通过getBaseContext()获取到他们的Context实例,不同的Activity或者Service实例他们的Context都是相互独立的,不会复用。
  • BroadcastReceiver:和Activity以及Service不同,BroadcastReceiver本身并不是Context的子类,而是在回调函数onReceive()中由Android框架传入一个Context的实例。系统传入的这个Context实例是被阉割过的,它并不能调用registerReceiver()已经bindService()这两个函数
  • ContentProvider:同样的,ContentProvider也不是Context的子类。同样是在创建的时候系统给传一个Context实例,然后在ContentProvider中就可以通过getContext()函数来获取。如果调用者和ContentProvider处于一个相同的应用进程也就是说在同一个应用中调用ContentProvider的话,getContext()会返回应用的全局唯一Context实例。相反如果不在同一个进程,那么他们各自返回自己所在进程的Context实例。

错误使用将导致内存泄漏

错误的使用Context将导致内存泄漏,典型的例子是在实现单例模式的时候使用Context而出现的内存泄漏:

public class SingleInstance{
	private Context mContext;
	private static SingleInstance sInstance;
	private SingleInstance(Context context){
		mContext = context;
	}
	public static SingleInstance getInstance(Context context){
		if(sInstance == null){
			sInstance = new SingleInstance(context);
		}

		return sInstance;
	}
}

对于这个实例,如果在创建这个单例的时候传入的context是Activity或者Service的,那么在整个应用结束之前,这个单例会一直存在,从而到这当初传给它Context的Activity或者Service也会一直存在不会被垃圾回收,这样的话Activity或者Service中关联的其它View或者数据等等也就不会被释放,最后导致了内存泄漏。在这个单例模式中传入的正确Context必须是Application Context,因为它是应用全局唯一的。而且生命周期跟应用的声明周期是同步的。
对于这种问题,我们也可以在创建单例的时候,从根源就把这个隐患给避免掉,具体做法如下:

public class SingleInstance{
	private Context mContext;
	private static SingleInstance sInstance;
	private SingleInstance(Context context){
		mContext = context;
	}
	public static SingleInstance getInstance(Context context){
		if(sInstance == null){
			sInstance = new SingleInstance(context.getApplicationContext());
		}

		return sInstance;
	}
}

不同的Context的对比

不同的组件中的context功能是不一样的,总结起来如下:

功能ApplicationActivityServiceBroadcastReceiverContentProvider
显示dialogNOYESNONONO
启动ActivityNO[1]YESNO[1]NO[1]NO[1]
实现Layout inflationNO[2]YESNO[2]NO[2]NO[2]
启动ServiceYESYESYESYESYES
绑定ServiceYESYESYESYESNO
发送BroadcastYESYESYESYESYES
注册BroadcastYESYESYESYESNO[3]
加载资源 ResourceYESYESYESYESYES

NO[1]:表示对应的组件并不是不可以,而是不建议。因为这些组件会在新的Task中创建Activity而不是在原来的Task中创建
NO[2]:也是表示不建议,因为在非Activity中进行Layout Inflation,会使用系统默认的主题,而不是应用中设置的主题
NO[3]:表示在Android4.2以及以上的系统中,如果注册BroadcastReceiver是null时也是可以的,用来获取sticky广播的当前值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值