注:本文翻译自Context, What Context?,原文链接在这里,作者是Dave Smith。ps:译者链接http://blog.csdn.net/race604/article/details/9331807

Context可能是Android应用中最常用的元素,而它也可能是最容易误用的。

Context对象是如此常见和传递使用,它可能会很容易产生并不是你预期的情形。加载资源、启动一个新的Activity、获取系统服务、获取内部文件路径以及创建view(其实还远不止这些)统统都需要Context对象来完成。我(原文作者)想做的只是给大家提供一些Context是如何工作的见解,以及让大家在应用中更有效的使用Context的技巧。

Context的类型

并不是所有的context实例都是等价的。根据Android应用的组件不同,你访问的context推向有些细微的差别。

Application - 是一个运行在你的应用进程中的单例。在Activity或者Service中,它可以通过getApplication()函数获得,或者人和继承于context的对象中,通过getApplicationContext()方法获得。不管你是通过何种方法在哪里获得的,在一个进程内,你总是获得到同一个实例。

Activity/Service - 继承于ContextWrapper,它实现了与context同样API,但是代理这些方法调用到内部隐藏的Context实例,即我们所知道的基础context。任何时候当系统创建一个新的Activity或者Service实例的时候,它也创建一个新的ContextImpl实例来做所有的繁重的工作。每一个Activity和Service以及其对应的基础context,对每个实例来说都是唯一的。

BroadcastReciver - 它本身不是context,也没有context在它里面,但是每当一个新的广播到达的时候,框架都传递一个context对象到onReceive()。这个context是一个ReceiverRestrictedContext实例,它有两个主要函数被禁掉:registerReceiver()和bindService()。这两个函数在BroadcastReceiver.onReceive()不允许调用。每次Receiver处理一个广播,传递进来的context都是一个新的实例。

ContentProvider - 它本身也不是一个Context,但是它可以通过getContext()函数给你一个Context对象。如果ContentProvider是在调用者的的本地(例如,在同一个应用进程),getContext()将返回的是Application单例。然而,如果调用这和ContentProvider在不同的进程的时候,它将返回一个新创建的实例代表这个Provider所运行的包。

保存引用

第一个我们需要解决问题是,在一个对象或者类内部保存一个context引用,而它生命周期却超过其保存引用的对象的生命周期。例如,创建一个自定义的单例,它需要一个context来加载资源或者获取ContentProvider,从而保存一个指向当前Activiy或者Service的引用在单例中。

糟糕的单例

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

这里的问题在于,我们不知道这个context是从哪里来的,并且如果保存一个最终指向的是Activity或者Servece的引用是并不安全的。这是一个问题,是因为一个单例在类的内部维持一个唯一的静态引用,这意味着我们的对象,以及所有其他它所引用的对象,将永远不能被垃圾回收。假如这个Context是一个Activity,我们将保存与这个Activity相关的所有的view以及其他大的对象,从而造成内存泄漏。

为了解决这个问题,我们修改单例永远只是保存Application context:

改善的单例:

public class CustomManager {
private static CustomManager sInstance; public static CustomManager getInstance(Context context) {
if (sInstance == null) {
//Always pass in the Application Context
sInstance = new CustomManager(context.getApplicationContext());
} return sInstance;
} private Context mContext; private CustomManager(Context context) {
mContext = context;
}
}

现在这个例子中,我们的Context来自哪里都没有关系,因为我们这里保存引用是安全的。Application  Context 本身就是一个单例,所以我们再创建另外一个static引用,不会造成任何内存泄漏。另外一个很好的例子是,在后台线程或者一个等待的Handler中保存Context的引用,也可以使用这样的方法。

为什么我们不能总是引用Application context呢?正如前面说的,引用Application context永远不用担心内存泄漏的问题。问题的答案,就像我在开始的介绍中说的,是因为不同context并不是等价的。

Context的能力

Conext能做的通用操作决定于这个context最初来源于哪里。下表所列的是,在应用中常见的会收到context对象的,以及对应的每种情况,它可以用于哪些地方:

  Application Activity Service ContentProvider BroadcastReceiver
Show a Dialog NO YES NO NO NO
Start an Activity NO1 YES NO1 NO1 NO1
Layout Inflation NO2 YES NO2 NO2 NO2
Start a Service YES YES YES YES YES
Bind to a Service YES YES YES YES NO
Send a Broadcast YES YES YES YES YES
Register BroadcastReceiver YES YES YES YES NO3
Load Resource Values YES YES YES YES YES

注:NO1 表示Application context的确可以开始一个Activity,但是它需要创建一个新的task。这可能会满足一些特定的需求,但是在你的应用中会创建一个不标准的回退栈(back stack),这通常是不推荐的或者不是是好的实践。

NO2 表示这是非法的,但是这个填充(inflation)的确可以完成,但是是使用所运行的系统默认的主题(theme),而不是你app定义的主题。

NO3 在Android4.2以上,如果Receiver是null的话(这是用来获取一个sticky broadcast的当前 值的),这是允许的。

用户界面UI

从前面的表格中可以看到,application context有很多功能并不是合适去做,而这些功能都与UI相关。实际上,只有Activity能够处理所有与UI相关的任务。其他类别的context实例功能都差不多。

幸运的是,在应用中这三种操作基本上都不需要在Activity范围之外进行,这很可能是android框架故意这么设计的。尝试显示一个使用Aplication context创建的Dialog,或者使用Application context开始一个Activity,系统会抛出一个异常,让你的application崩溃,非常强的告诉你某些地方出了问题。

一个并不明显的问题是填充布局(inflating layout)。如果你已经读过了我(原文作者)的上一篇文章Layout inflation,你就已经知道它可能是一个非常神秘过程,伴随一些隐藏的行为。使用正确的context关系到其中的一个行为。当你使用Application context来inflate一个布局的时候,框架并不会报错,并返回一个使用系统默认的主题创建一个完美的view给你,而没有考虑你的applicaiton自定义的theme和style。这是因为Acitivity是唯一的绑定了在manifast文件种定义主题的Context。其他的Context实例将会使用系统默认的主题来inflater你的view。导致显示的结果并不是你所希望的。

规则的路口

可能有些读者已经得出两个规则互相矛盾的结论。可能有些情况下,在某些Application的设计中,我们可能既必须长期保存一个的引用,并且为了完成与UI相关的工作又必须保存一个Activity。如果出现这种情况,我将会强烈建议你重新考虑你的设计,它将是一个很好的“反框架”教材。

经验法则

绝大多数情况下,使用在你的所工作的组建内部能够直接获取的Context。只要这个引用没有超过这个组建的生命周期,你可以安全的保存这个引用。一旦你要保存一个context的引用,它超过了你的Activity或者Service的生命周期范围,甚至是暂时的,你就需要转换你的引用为Application context。

原文: http://www.race604.com/android-context-intro/

 

Android中,Context,什么是Context?的更多相关文章

  1. Android中的创建型模式总结

    共5种,单例模式.工厂方法模式.抽象工厂模式.建造者模式.原型模式 单例模式 定义:确保某一个类的实例只有一个,而且向其他类提供这个实例. 单例模式的使用场景:某个类的创建需要消耗大量资源,new一个 ...

  2. Android中Context详解

    大家好,  今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友-----Context类 ,说它熟悉,是应为我们在开发中时刻的在与它打交道,例如:Service.BroadcastReceiver.A ...

  3. Android中的Context

    Context用来访问全局信息的接口,比如影城程序的资源.一些常用的组件都是继承自Context,目的就是方便的访问资源,比如Activity, Service.... 从Context访问本组件的资 ...

  4. iOS的 context 和Android 中的 canvas

    ios 想要绘图,要用到CGContextRef类.最基本的用法是在- (void)drawRect:(CGRect)rect 函数中绘制. Android 中要用到Canvas类.最基本的用法是在  ...

  5. Android中Context详解 ---- 你所不知道的Context

    转自:http://blog.csdn.net/qinjuning/article/details/7310620Android中Context详解 ---- 你所不知道的Context 大家好,  ...

  6. Android中的Context详解

    前言:本文是我读<Android内核剖析>第7章 后形成的读书笔记 ,在此向欲了解Android框架的书籍推荐此书. 大家好,  今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友---- ...

  7. 转:Android中Context详解 ---- 你所不知道的Context

    转:http://blog.csdn.net/qinjuning/article/details/7310620 转:http://blog.csdn.net/lmj623565791/article ...

  8. Android中Context具体解释 ---- 你所不知道的Context

                                                                                                         ...

  9. (四)Android中Context的理解与使用

    一.Context的作用 Context可用于访问全局资源. public class MainActivity extends Activity { private TextView tv; @Ov ...

随机推荐

  1. tp5 中 model 的查询方法

    实例化模型后调用查询方法,可以写任何想要的查询(推荐) public function select(){ $user = model('User'); $data = $user -> ) - ...

  2. iOS开发的小技巧

    转自简书:http://www.jianshu.com/p/50b63a221f09  http://www.jianshu.com/p/08f194e9904c 原作者:叶孤城___ self.ta ...

  3. Linux常用命令学习7---(磁盘管理df du、磁盘的分区和格式化fdisk parted)

    1.磁盘管理    在服务器的维护中,我们需要关心服务器的磁盘使用了多少.还有多少的剩余空间.某个文件有多大.某个文件夹内的所有文件在一起一共占用的多少空间……问题.以便我们在合适的时机为服务器添加硬 ...

  4. 特征检测之Haar

    Harr特征, 主要用于人脸检测,可以参考我的博文 基于MATLAB的adaboost级联形式的人脸检测实现 1 harr特征的原理 2 haar特征的计算 3 haar特征的应用

  5. 在ionic这个框架下(Angular JS),对URL进行重写,过滤掉URL中的#号

    此时URL的改变已经完全不受后台代码控制了,因此我们要在前端的ionic这个框架和IIS中进行修改调控. 其实IIS只是host了整个站点,具体的URL跳转都是由前端来控制的. 1):那么前端要加上一 ...

  6. 浏览器-05 HTML和CSS解析1

    一个浏览器内核几个主要部分,HTML/CSS解析器,网络处理,JavaScript引擎,2D/3D图形引擎,多媒体支持等; HTML 解析和 DOM 网页基本结构 一个网页(Page),每个Page都 ...

  7. 数据库密码爆破HexorBase

    数据库密码爆破HexorBase   数据库服务是服务器上最常见的一类服务.由于数据库保存大量的敏感信息,所以它的安全非常重要.测试数据库服务安全的重要方式,就是检查口令的强壮度.   Kali Li ...

  8. 00 MySQL

    1数据库 1.1名词解释      DB:数据库Database,用于存放数据仓库      DBMS:数据库管理系统 DataBase Management System,管理数据库      ta ...

  9. jQuery插件(多级菜单)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. 【MongoDB初识】-增删改

    1.切换数据库 admin数据库:use admin test数据库:use test 2.新增: 方法一(首选) c} db.class.save(c) 或者db.class.insert(c) 方 ...