1、sdk当中关于Context的介绍

Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.

http://developer.android.com/reference/android/content/Context.html

Context提供了关于应用环境全局信息的接口。它是一个抽象类,它的由整个Android应用程序所实现。它允许获取应用当中特定的资源和类,同时允许调用应用级的操作,如启动Activity,broadcasting和接收intents等等。

从以上的描述当中,我们基本获得不了什么信息,更无法理性的认识Context。

我们再来看看Context是子类和部分方法如下:


其中Application、Activity、Service等我们在开发当中常用的类,都是其子类,我们在这里也无法认识到它的作用。右图,我们可以看到,我们平时用到的startActivty();startService();等方法都在这里,在这里,我们可以看到Context的第一个作用:

2、第一个作用

Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system.

他提供一个全局的接口,并且这些接口由Android应用程序当中特定的类实现。

我们再来看看Activity的源码:

 /**     * Launch a new activity.  You will not receive any information about when     * the activity exits.  This implementation overrides the base version,     * providing information about     * the activity performing the launch.  Because of this additional     * information, the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag is not     * required; if not specified, the new activity will be added to the     * task of the caller.     *      * <p>This method throws {@link android.content.ActivityNotFoundException}     * if there was no Activity found to run the given Intent.     *      * @param intent The intent to start.      *      * @throws android.content.ActivityNotFoundException     *      * @see #startActivityForResult      */    @Override    public void startActivity(Intent intent) {        startActivityForResult(intent, -1);    }
  public void startActivityForResult(Intent intent, int requestCode) {        if (mParent == null) {            Instrumentation.ActivityResult ar =                mInstrumentation.execStartActivity(                    this, mMainThread.getApplicationThread(), mToken, this,                    intent, requestCode);            if (ar != null) {                mMainThread.sendActivityResult(                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),                    ar.getResultData());            }            if (requestCode >= 0) {                // If this start is requesting a result, we can avoid making                // the activity visible until the result is received.  Setting                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the                // activity hidden during this time, to avoid flickering.                // This can only be done when a result is requested because                // that guarantees we will get information back when the                // activity is finished, no matter what happens to it.                mStartedActivity = true;            }        } else {            mParent.startActivityFromChild(this, intent, requestCode);        }    }
  

这里,startActivity()的实现调用了Context中没有的startActivityForResult方法得以实现开启新的窗体的Activity的功能。

我们再看看我们平时用到的startService方法,非常遗憾我们没有在Activity当中找到startService的实现,但是我们继续往上找,找到了ContentWrapper时,我们找到了startService的实现

 @Override    public ComponentName startService(Intent service) {        return mBase.startService(service);    }
类似的Application,service等,都可以找到其相应的函数的实现。Context功能之一就是将常用的公共方法抽取出来,然后由各个组件实现,这真是第一句话的意思。

3、第二个作用

It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.

它允许获取应用当中特定的资源和类,同时允许调用应用级的操作,如启动Activity,broadcasting和接收intents等等。其实该类为LONG型,类似Win32中的Handle句柄,很多方法需要通过 Context才能识别调用者的实例,比如说Toast的第一个参数就是Context,一般在Activity中我们直接用this代替,代表调用者的 实例为Activity,而到了一个button的onClick(View view)等方法时,我们用this时就会报错,所以我们可能使用ActivityName.this来解决,主要原因是因为实现Context的类主要有Android特有的几个模型,Activity、Service以及BroadcastReceiver。

对于以上几句话的理解,我们可以看看TextView的构造函数


可以看到起参数为Context但是我们在实际开发当中

TextView text1 = new TextView(this);TextView text2 = new TextView(getApplication());TextView text3 = new TextView(getApplicationContext());
这两种定义都可以实现。this表示这个类的某个实例,而getApplicationContext()得到的是Context(),两个风马牛不相及的事物为什么能放在TextView的构造函数里,而不报错呢,这就是Context的第二个作用,句柄。 标识应用程序中的不同对象和同类对象中的不同的实例。

4、两种不同的Context

正如上段代码,getApplication();getApplicationContext();前者是在Activity当中定义的,而后者是在Context当中定义的。 两者的说明分别为: 这里,我们看到了两种不同的Context:Activity所拥有的Context和全局的Context。
这是两种不同的context,也是最常见的两种。第一种中context的生命周期与Application的生命周期相关的,context随着Application的销毁而销毁,伴随application的一生,与activity的生命周期无关。第二种中的context跟Activity的生命周期是相关的,但是对一个Application来说,Activity可以销毁几次,那么属于Activity的context就会销毁多次。至于用哪种context,得看应用场景,个人感觉用Activity的context好一点,不过也有的时候必须使用Application的context。application context可以通过Context.getApplicationContext或者Activity.getApplication方法获取。

5、内存泄露

在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 controllabel.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 {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 viewsetContentView(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方法获取。

6、避免context相关的内存泄露,记住以下几点:

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

7、制造Application context的方法

Java里面通常是用一个static的变量(例如singleton之类的)来同步activity之间(程序里面类之间)的状态。在android里面比较靠谱的做法是用application context来关联这些状态。
每个activity都是context,里面包含了运行时的状态。同样application也有一个context,android会保证这个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 {@Overridepublic void onCreate(Bundle b){...MyApp appState = ((MyApp)getApplicationContext());String state = appState.getState();...}}

小文章,边看边写,欢迎纠错。
参考文章:http://www.igniu.com/?p=215 http://blog.csdn.net/aomandeshangxiao/article/details/7008636


更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. Android实现冒泡效果进度条
  5. android camera2 api点击图片实现聚焦
  6. Android(安卓)自定义SeekBar显示进度百分比
  7. Android(安卓)导航条效果实现(六) TabLayout+ViewPager+Fragment
  8. android——ListView功能的实现(使用simpleAdapter)
  9. android实现自动提示功能

随机推荐

  1. 【Android】Error[*,*]Could not find met
  2. iOS Airplay--Airtunes音乐播放在Android
  3. android sdk配置
  4. Android(安卓)页面自动切换实现
  5. android 驱动(6)---DTS 分析
  6. Android 布局属性 Android:layout_weight
  7. android平台下UITesting环境配置
  8. 谷歌宣布Android Studio将取代Eclipse
  9. 使用Jenkins做Java、Android项目开发持续
  10. Android开发工具Android Studio、Android