在android中我们经常遇到这样的情况,在创建一个对象的时候往往需要传递一个this参数,比如:语句 MyView mView = new MyView(this),要求传递一个this参数,这个this究竟指的是什么东西呢? 其实这里的this指的就是当前的Activity.this,是这个语句所在的Activity的this。Activity.this取的是这个Activity的Context,那么这个Context究竟是什么东西呢?它起到什么作用呢?

  Context 按照英文字面意思就是"上下文",它位于位于framework package的android.content.Context中,其实该类为LONG型,类似于句柄。很多方法需要通过 Context才能识别调用者的实例。

Context提供了关于应用环境全局信息的接口。它是一个抽象类,它的执行被Android系统所提供。它允许获取以应用为特征的资源和类型。同时启动应用级的操作,如启动一个Activity,发送广播,接受Intent

Context继承关系如下:

Context有两种类型

androidcontext可以作很多操作,但是最主要的功能是加载和访问资源。在android中有两种context,一种是 application context,一种是activity context。

补充:

getApplicationContext() 返回应用的上下文,生命周期是整个应用,应用摧毁它才摧毁

Activity.this的context 返回当前activity的上下文,属于activity ,activity 摧毁他就摧毁

getBaseContext()  返回由构造函数指定或setBaseContext()设置的上下文,一般不常用。

(1)activity context

通常我们在各种类和方法间传递的是activity context。比如一个activity的onCreate

protected void onCreate(Bundle state) {
super.onCreate(state);
 
TextView label = new TextView(this);

//传递context给view control

label.setText("Leaks are bad");
 
setContentView(label);
}

把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity占有的资源:view hierachy, resource等。

内存泄露

context发生内存泄露的话,就会泄露很多内存。这里泄露的意思是gc没有办法回收activity的内存。

注释:为什么GC没有办法回收相应的内存,个人感觉是因为传递Context会增加对象指针的引用计数,所以基于智能指针技术的GC无法释放相应的内存。

当屏幕旋转的时候,系统会销毁当前的activity,保存状态信息,再创建一个新的。比如我们写了一个应用程序,它需要加载一个很大的图片,我们不希望每次旋转屏幕的时候都销毁这个图片,重新加载。实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类创建销毁它始终保存在内存中。实现类似:

public class myactivity extends Activity {
private static Drawable sBackground;
protected void onCreate(Bundle state) {
super.onCreate(state); TextView label = new TextView(this);
label.setText("Leaks are bad"); if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);//drawable attached to a view setContentView(label);
}
}

  这段程序看起来很简单,但是却问题很大。当屏幕旋转的时候会有leak(即gc没法销毁activity)。我们刚才说过,屏幕旋转的时候系统会销毁当前的activity。但是当drawable和view关联后,drawable保存了view的 reference,即sBackground保存了label的引用,而label保存了activity的引用。既然drawable不能销毁,它所引用和间接引用的都不能销毁,这样系统就没有办法销毁当前的activity,于是造成了内存泄露。gc对这种类型的内存泄露是无能为力的。避免这种内存泄露的方法是避免activity中的任何对象的生命周期长过activity,避免由于对象对 activity的引用导致activity不能正常被销毁。

为了防止内存泄露,我们应该注意以下几点:

    1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
    2. 对于生命周期长的对象,可以使用application context
    3. 避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化

什么时候创建Context实例

熟悉了Context的继承关系后,我们接下来分析应用程序在什么情况需要创建Context对象的?应用程序创建Context实例的

情况有如下几种情况:

  1、创建Application 对象时, 而且整个App共一个Application对象

  2、创建Service对象时

  3、创建Activity对象时

因此应用程序App共有的Context数目公式为:

                     总Context实例个数 = Service个数 + Activity个数 + 1(Application对应的Context实例)

具体创建Context的时机

1、创建Application对象的时机

  每个应用程序在第一次启动时,都会首先创建Application对象。如果对应用程序启动一个Activity(startActivity)流程比较

清楚的话,创建Application的时机在创建handleBindApplication()方法中,该函数位于 ActivityThread.java类中 ,如下:

 //创建Application时同时创建的ContextIml实例
private final void handleBindApplication(AppBindData data){

///创建Application对象
Application app = data.info.makeApplication(data.restrictedBackupMode, null);

}
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {

try {
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = new ContextImpl(); //创建一个ContextImpl对象实例
appContext.init(this, null, mActivityThread); //初始化该ContextIml实例的相关属性
///新建一个Application对象
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app); //将该Application实例传递给该ContextImpl实例
}

}

2、创建Activity对象的时机

通过startActivity()或startActivityForResult()请求启动一个Activity时,如果系统检测需要新建一个Activity对象时,就会

回调handleLaunchActivity()方法,该方法继而调用performLaunchActivity()方法,去创建一个Activity实例,并且回调

onCreate(),onStart()方法等, 函数都位于 ActivityThread.java类 ,如下:

//创建一个Activity实例时同时创建ContextIml实例
private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {

Activity a = performLaunchActivity(r, customIntent); //启动一个Activity
}
private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {

Activity activity = null;
try {
//创建一个Activity对象实例
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
}
if (activity != null) {
ContextImpl appContext = new ContextImpl(); //创建一个Activity实例
appContext.init(r.packageInfo, r.token, this); //初始化该ContextIml实例的相关属性
appContext.setOuterContext(activity); //将该Activity信息传递给该ContextImpl实例

}

}

3、创建Service对象的时机

通过startService或者bindService时,如果系统检测到需要新创建一个Service实例,就会回调handleCreateService()方法,

完成相关数据操作。handleCreateService()函数位于 ActivityThread.java类,如下:

 //创建一个Service实例时同时创建ContextIml实例
private final void handleCreateService(CreateServiceData data){

//创建一个Service实例
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
}

ContextImpl context = new ContextImpl(); //创建一个ContextImpl对象实例
context.init(packageInfo, null, this); //初始化该ContextIml实例的相关属性
//获得我们之前创建的Application对象信息
Application app = packageInfo.makeApplication(false, mInstrumentation);
//将该Service信息传递给该ContextImpl实例
context.setOuterContext(service);

}

  另外,需要强调一点的是,通过对ContextImp的分析可知,其方法的大多数操作都是直接调用其属性mPackageInfo(该属性类

型为PackageInfo)的相关方法而来。这说明ContextImp是一种轻量级类,而PackageInfo才是真正重量级的类。而一个App里的

所有ContextIml实例,都对应同一个packageInfo对象。

(2)application context

生命周期: application context生命周期比较长,伴随应用程序的存在而存在,与activity的生命周期无关。

获取: application context可以通过Context.getApplicationContext或者Activity.getApplication方法获取。

Java里面通常是用一个static的变量(例如singleton之类的)来同步activity之间(程序里面类之间)的状态。在android里面比较靠谱的做法是用application context来关联这些状态。

每个activity都是context,里面包含了运行时的状态。同样application也有一个contextandroid会保证这个context是唯一的实例。

做一个你自己的application context需要继承android.app.Application,然后在app的manifest里面说明这个类。android会自动帮你创建你这个类的实例,接着你用Context.getApplicationContext()方法就能在各个activity里面获得这个application context了。

class MyApp extends Application {

  private String myState;

  public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
} class Blah extends Activity { @Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}

Android中Context的总结及其用法的更多相关文章

  1. Android中Context详解 ---- 你所不知道的Context(转)

    Android中Context详解 ---- 你所不知道的Context(转)                                               本文出处 :http://b ...

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

                                                                                                         ...

  3. Android中Context详解

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

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

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

  5. Android中的Handler的具体用法

    Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行.Android利用Handler来实现UI线程的更新的. Handler是Android中的消息发送器,其在哪个Activit ...

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

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

  7. Android中Parcelable与Serializable接口用法

    转自: Android中Parcelable接口用法 1. Parcelable接口 Interface for classes whose instances can be written to a ...

  8. android 中context的具体作用和意义

    context在android中是非常重要的一个类,此类一般用于activity之中 从字面意思来看,这是环境变量,内部实现了一些方法,但是此类也可以看做是一个句柄,用来唯一标示activity 举个 ...

  9. Android中Context解析

    Context概念 当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context. Context是一个抽象基类,我们通过它访问当前包的资源(getResources.getA ...

随机推荐

  1. nginx 域名跳转 Nginx跳转自动到带www域名规则配置、nginx多域名向主域名跳转

    nginx 域名跳转 Nginx跳转自动到www域名规则配置,如果设置使 mgcrazy.com域名在用户访问的时候自动跳转到 www.mgcrazy.com呢?在网上找了好多资料都没有一个完整能解决 ...

  2. QPS相关的概念收集(吞吐量(TPS)、QPS、并发数、响应时间(RT))

    一.概念: 1.响应时间(RT) 响应时间是指系统对请求作出响应的时间.直观上看,这个指标与人对软件性能的主观感受是非常一致的,因为它完整地记录了整个计算机系统处理请求的时间.由于一个系统通常会提供许 ...

  3. mqtt 协议之 PINGREQ, PINGRESP

    mqtt 协议里最简单的是 ping 协议吧 (心跳包), ping 协议是已连接的客户端发往服务端, 告诉服务端,我还"活着" PINGREQ - PING request fi ...

  4. WPF Interaction框架简介(一)——Behavior

    在WPF 4.0中,引入了一个比较实用的库——Interactions,这个库主要是通过附加属性来对UI控件注入一些新的功能,除了内置了一系列比较好用的功能外,还提供了比较良好的扩展接口.本文这里简单 ...

  5. 翻译:Spring-Framework-Reference Document:11-Transaction Management

    TUESDAY, 07 APRIL Comprehensive transaction support is the most compelling reasons to use the Spring ...

  6. fiddler抓取手机上https数据配置和失败的解决办法

    1. 设置fiddler,Tools-Options...      抓取https的话,勾选红框中的内容 2. fiddler默认监听端口8888 3. 查看本机IP 4. 打开手机 设置-无线局域 ...

  7. 十一.spring-boot 添加http自动转向https

    SSL是为网络通信提供安全以及保证数据完整性的的一种安全协议,SSL在网络传输层对网络连接进行加密. 例:cas 的单点登陆就用到了SSL 一.安全证书的生成 1.可以使用jdk自带的证书生成工具,j ...

  8. B. Suffix Structures 模拟吧,情况比較多要想周全

    这道题须要考虑的情况比較多,flag1表示情况是:b数组里有的字母而a里没有和b里面的同一个字母个数比a里面的多 flag2表示情况:b里面的左右字母能不能在a中同等顺序的存在 flag3表示情况:a ...

  9. [转]SSIS error DTS_E_CANNOTACQUIRECONNECTIONFROMCONNECTIONMANAGER when connecting to Oracle data source

    本文转自:http://blogs.msdn.com/b/jorgepc/archive/2008/02/12/ssis-error-dts-e-cannotacquireconnectionfrom ...

  10. arithmetic-slices

    https://leetcode.com/problems/arithmetic-slices/ public class Solution { public int numberOfArithmet ...