Android中Context解析
Context概念
当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context。
Context是一个抽象基类,我们通过它访问当前包的资源(getResources、getAssets)和启动其他组件(Activity、Service、Broadcast)以及得到各种服务(getSystemService),当然,通过Context能得到的不仅仅只有上述这些内容。对Context的理解可以来说:Context提供了一个应用的运行环境,在Context的大环境里,应用才可以访问资源,才能完成和其他组件、服务的交互,Context定义了一套基本的功能接口,可以理解为一套规范,而Activity和Service是实现这套规范的子类,这么说也许并不准确,因为这套规范实际是被ContextImpl类统一实现的,Activity和Service只是继承并有选择性地重写了某些规范的实现。
activity继承关系:
Service和Application:

可以看到Activity、Service、Application都是Context的子类;也就是说,Android系统的角度来理解:Context是一个场景,代表与操作系统的交互的一种过程。从程序的角度上来理解:Context是个抽象类,而Activity、Service、Application等都是该类的一个实现。
在仔细看一下上图:Activity、Service、Application都是继承自ContextWrapper,而ContextWrapper内部会包含一个base context,由这个base context去实现了绝大多数的方法。
Context的继承结构还是稍微有点复杂的,可以看到,直系子类有两个,一个是ContextWrapper,一个是ContextImpl。那么从名字上就可以看出,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类。而ContextWrapper又有三个直接的子类,ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一个带主题的封装类,而它有一个直接子类就是Activity。
那么在这里我们至少看到了几个所比较熟悉的面孔,Activity、Service、还有Application。由此,其实我们就已经可以得出结论了,Context一共有三种类型,分别是Application、Activity和Service。这三个类虽然分别各种承担着不同的作用,但它们都属于Context的一种,而它们具体Context的功能则是由ContextImpl类去实现的。
那么Context到底可以实现哪些功能呢?这个就实在是太多了,弹出Toast、启动Activity、启动Service、发送广播、操作数据库等都需要用到Context。由于Context的具体能力是由ContextImpl类去实现的,因此在绝大多数场景下,Activity、Service和Application这三种类型的Context都是可以通用的。不过有几种场景比较特殊,比如启动Activity,还有弹出Dialog。出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。
一个应用中Context的数量等于Activity的个数 + Service的个数 + 1,这个1为Application
Context与ApplicationContext
看了标题,千万不要被误解,ApplicationContext并没有这个类,其实更应该叫做:Activity与Application在作为Context时的区别。嗯,的确是这样的,大家在需要Context的时候,如果是在Activity中,大多直接传个this,当在匿名内部类的时候,因为this不能用,需要写XXXActivity.this,很多哥们会偷懒,直接就来个getApplicationContext。那么大家有没有想过,XXXActivity.this和getApplicationContext的区别呢?
XXXActivity和getApplicationContext返回的肯定不是一个对象,一个是当前Activity的实例,一个是项目的Application的实例。既然区别这么明显,那么各自的使用场景肯定不同,乱使用可能会带来一些问题。
下面开始介绍在使用Context时,需要注意的问题。
引用的保持
大家在编写一些类时,例如工具类,可能会编写成单例的方式,这些工具类大多需要去访问资源,也就说需要Context的参与。
在这样的情况下,就需要注意Context的引用问题。
例如以下的写法:
- package com.mooc.shader.roundimageview;
- import android.content.Context;
- public class CustomManager
- {
- private static CustomManager sInstance;
- private Context mContext;
- private CustomManager(Context context)
- {
- this.mContext = context;
- }
- public static synchronized CustomManager getInstance(Context context)
- {
- if (sInstance == null)
- {
- sInstance = new CustomManager(context);
- }
- return sInstance;
- }
- //some methods
- private void someOtherMethodNeedContext()
- {
- }
- }
对于上述的单例,大家应该都不陌生(请别计较getInstance的效率问题),内部保持了一个Context的引用;
这么写是没有问题的,问题在于,这个Context哪来的我们不能确定,很大的可能性,你在某个Activity里面为了方便,直接传了个this;这样问题就来了,我们的这个类中的sInstance是一个static且强引用的,在其内部引用了一个Activity作为Context,也就是说,我们的这个Activity只要我们的项目活着,就没有办法进行内存回收。而我们的Activity的生命周期肯定没这么长,所以造成了内存泄漏。
那么,我们如何才能避免这样的问题呢?
有人会说,我们可以软引用,嗯,软引用,假如被回收了,你不怕NullPointException么。
把上述代码做下修改:
- public static synchronized CustomManager getInstance(Context context)
- {
- if (sInstance == null)
- {
- sInstance = new CustomManager(context.getApplicationContext());
- }
- return sInstance;
- }
这样,我们就解决了内存泄漏的问题,因为我们引用的是一个ApplicationContext,它的生命周期和我们的单例对象一致。
这样的话,可能有人会说,早说嘛,那我们以后都这么用不就行了,很遗憾的说,不行。上面我们已经说过,Context和Application Context的区别是很大的,也就是说,他们的应用场景(你也可以认为是能力)是不同的,并非所有Activity为Context的场景,Application Context都能搞定。
下面就开始介绍各种Context的应用场景。
Context的应用场景
大家注意看到有一些NO上添加了一些数字,其实这些从能力上来说是YES,但是为什么说是NO呢?下面一个一个解释:
数字1:启动Activity在这些类中是可以的,但是需要创建一个新的task。一般情况不推荐。
数字2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。
数字3:在receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值。(可以无视)
注:ContentProvider、BroadcastReceiver之所以在上述表格中,是因为在其内部方法中都有一个context用于使用。
好了,这里我们看下表格,重点看Activity和Application,可以看到,和UI相关的方法基本都不建议或者不可使用Application,并且,前三个操作基本不可能在Application中出现。实际上,只要把握住一点,凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以,当然了,注意Context引用的持有,防止内存泄漏。
Android中Context解析的更多相关文章
- Android中XML解析-Dom解析
Android中需要解析服务器端传过来的数据,由于XML是与平台无关的特性,被广泛运用于数据通信中,有的时候需要解析xml数据,格式有三种方式,分别是DOM.SAX以及PULL三种方式,本文就简单以D ...
- Android中Context的总结及其用法
在android中我们经常遇到这样的情况,在创建一个对象的时候往往需要传递一个this参数,比如:语句 MyView mView = new MyView(this),要求传递一个this参数,这个t ...
- Android中Context详解 ---- 你所不知道的Context(转)
Android中Context详解 ---- 你所不知道的Context(转) 本文出处 :http://b ...
- Android中Context详解
大家好, 今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友-----Context类 ,说它熟悉,是应为我们在开发中时刻的在与它打交道,例如:Service.BroadcastReceiver.A ...
- Android中XML解析
package com.example.thebroadproject; public class Book { private int id; private String name; privat ...
- Android中Context详解 ---- 你所不知道的Context
转自:http://blog.csdn.net/qinjuning/article/details/7310620Android中Context详解 ---- 你所不知道的Context 大家好, ...
- 转:Android中Context详解 ---- 你所不知道的Context
转:http://blog.csdn.net/qinjuning/article/details/7310620 转:http://blog.csdn.net/lmj623565791/article ...
- Android中Context具体解释 ---- 你所不知道的Context
...
- Android中XML解析-SAX解析
昨天由于时间比较匆忙只写了Android中的XML解析的Dom方式,这种方式比较方便,很容易理解,最大的不足就是内容多的时候,会消耗内存.SAX(Simple API for XML)是一个解析速度快 ...
随机推荐
- LeetCode 982. Triples with Bitwise AND Equal To Zero
题目链接:https://leetcode.com/problems/triples-with-bitwise-and-equal-to-zero/ 题意,已知数组A,长度不超过1000,最大的数不超 ...
- Day10 类与对象-面向对象编程(1)
面向对象编程(OOP) 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据. 抽象 三大特征: 封装 继承 多态 从认识论角度考虑是先有对象后有类.对象,是具体的事物.类,是抽象的, ...
- Vue中Object和Array数据变化侦测原理
在学完Vue.js框架,完成了一个SPA项目后,一直想抽时间找本讲解Vue.js内部实现原理的书来看看,经过多方打听之后,我最后选择了<深入浅出Vue.js>这本书.然而惭愧的是,这本书已 ...
- Word中的代码怎样语法高亮
在平常我们粘贴代码到Word中的时候,经常会遇到代码粘贴到Word中后没有语法高亮,看着很乱很不友好,Word自带的样式---语法使用着也不尽人意, 网上有很多做法可以使得在插入在Word中的代码能够 ...
- odoo视图 “动作” 里添加菜单按钮:案例
####################################################################################odoo中常用方法,在动作里面添 ...
- C++模板封装Win32 API 动态调用
起因 花两周通读了一遍<C++ Primer>,积攒的疑惑一扫而光. 前因 利用C++11可变模板,封装调用dll导出函数 本以为已经很好用了,最近抽时间巩固下知识体系,发现自己道行不够! ...
- python之 数据类型限制
问题增加类型限制 NameError: name 'List' is not defined def twoSum(self, nums: List[int], target: int) -> ...
- 🏆【Java技术专区】「探针Agent专题」Java Agent探针的技术介绍(1)
前提概要 Java调式.热部署.JVM背后的支持者Java Agent: 各个 Java IDE 的调试功能,例如 eclipse.IntelliJ : 热部署功能,例如 JRebel.XRebel. ...
- SpringBoot自动装配-源码分析
1. 简介 通过源码探究SpringBoot的自动装配功能. 2. 核心代码 2.1 启动类 我们都知道SpringBoot项目创建好后,会自动生成一个当前模块的启动类.如下: import org. ...
- DC-6 靶机渗透测试
DC-6 渗透测试 冲冲冲,好好学习 . 收获总结写在文末. 操作机:kali 172.66.66.129 靶机:DC-4 172.66.66.136 网络模式:NAT 上来一波 netdiscove ...