Context而是一个类——如果不太了解面向对象,可以把“类”看做一种数据类型,就像int,不过类型为“类”的数据(称为对象)可能储存远比int多的信息,比如这里的类型为Context的对象就储存关于程序、窗口的一些资源。 有些函数调用时需要一个Context参数,比如Toast.makeText,因为函数需要知道是在哪个界面中显示的Toast。 再比如,Button myButton = new Button(this); 这里也需要Context参数(this),表示这个按钮是在“this”这个屏幕中显示的。 Android开发使用(纯粹的)面向对象语言,一切都是对象,就连我们写的函数都是对象的函数。 public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toast.makeText(this, "OK!", Toast.LENGTH_LONG).show(); Button button1 = (Button)findViewById(R.id.button1); button1.setOnClickListener(new Button.OnClickListener(){ public void onClick(View v) { Toast.makeText(MainActivity.this, "Hello, world!", Toast.LENGTH_LONG).show(); } }); } } 这里OnCreate就是MainActivity的对象的函数(MainActivity是类),所以这个函数中的this就表示当前的、包含这个函数的MainActivity对象。 MainActivity extends Activity,意思是MainActivity 继承 Activity,即MainActivity 是 Activity 的一种,所有的MainActivity 都是 Activity。同样,在Android文档中Activity继承ContextThemeWrapper,ContextThemeWrapper继承ContextWrapper,ContextWrapper继承Context。所以this这个MainActivity也是Context,把this传入Toast.makeText表示“OK!”是在当前的MainActivity对象(也是Context)中显示的。 对于显示"Hello, world!"的Toast.makeText,这个函数在onClick中,而onClick是new Button.OnClickListener(){...}这个没有名字的类的函数,this表示匿名类的对象,不表示MainActivity对象,所以这里用MainActivity.this,强制选择外面一层MainActivity的this。 PS:定向求助?我不记得我以前回答过Android方面的问题……难道是系统自动发的?
常规需要Context实例的方法主要有各种Service实现的类,比如说SensorManager在实例化时需要getSystemService(String)方法
在android中context可以作很多操作,但是最主要的功能是加载和访问资源。在android中有两种context,一种是 application context,
一种是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的内存。Leaking an entire activity是很容易的一件事。当屏幕旋转的时候,系统会销毁当前的activity,保存
状态信息,再创建一个新的。比如我们写了一个应用程序,它需要加载一个很大的图片,我们不希望每次旋转屏 幕的时候都销
毁这个图片,重新加载。实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类创建销毁它始终保存在内
存中。
实现类似:
public class myactivity extends Activity
{
privatestatic Drawable sBackground;
protectedvoid 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不能正常被销毁。我们可以
使用application context。application context伴随application的一生,与activity的生命周期无关。
application context可以通过Context.getApplicationContext或者Activity.getApplication方法获取。避免context相关
的内存泄露,记住以下几点:1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本
身生命周期是一样的2. 对于生命周期长的对象,可以使用application context3. 避免非静态的内部类,尽量使用静态类,避
免生命周期问题,注意内部类对外部对象引用导致的生命周期变化