【第一课】神奇的Context

初学Android的困惑

初学Android跳转页面的时候,往往教程里是这么写的:

1
2
3
4
Intent intent = new Intent();
//MyActivity就是当前的Activity,ItActivity就是目标Activity。
intent.setClass(MyActivity.this, ItActivity.class);
startActivityForResult(intent, 0);

当时可能想当然的把setClass()当作是传递了两个class进去,从而实现了class之间的某种“切换”动作。

但是如果你看看这个方法的参数就会发现它原型其实是这样的:

1
2
public android.content.Intent setClass(android.content.Context packageContext, java.lang.Class<?> cls)
//两个参数,第一个是Context类型的,第二个才是Class

那么什么是Context呢?为什么传递个MyActivity.this就相当于传递了Context呢?这些疑问先放到一边,我们先来看另一个困惑:

初学者常常会在某个Activity里写了太多太多的代码,其实心中是向往着“面向对象”的,也希望把很多复杂的逻辑功能封装成一个外部类,而不是写在Activity里面,搞很多内部类、内部函数。但阻碍这一想法的往往是写在外部类里怎么调用startActivity(),就好像新建了一个外部的类之后,就与Android断绝了某种联系了似的变成了一个独立的java代码块。

这些困惑的主要原因就是对Android理解不够深入,对Context还不了解。

字面理解Context

Context直接翻译成汉语可以翻译成:环境变量、上下文、来龙去脉。

只从字面翻译还是很形象的,你可以直接理解为它就是Android的环境。

做个小实验你可以直接在一个Activity里直接写这样一句:

1
Context context=getApplicationContext();

然后你用得到的这个context,后面加点,让IDE来自动提示你它有哪些方法。
我点几个常见的出来,是不是很眼熟?:

1
2
3
4
5
6
7
8
9
10
11
12
13
//启动Activity
context.startActivity(…);
//获得本地设置
context.getSharedPreferences(…);
//启动服务
context.startService(…);
//发送广播
context.sendBroadcast(…);
//获得系统Service(控制设备)
context.getSystemService(…);
//获得资源
context.getResources();
……

你要操作Android的什么?系统管理、组件的开启调用、访问资源应有尽有,想做什么做什么!

这时候,是不是就可以在外部定义各种复杂逻辑的class了?只需通过构造函数传递一个Context,想怎么操作Android都没有问题。

Context的子类

现在你知道了,Context是一个高度抽象的“大环境”。那么为啥Intent传递参数的时候第一个参数是Context,你却可以写一个MyActivity.this呢?

这其实也很容易想到(善于读API和源码的小伙伴不要嘲讽……)。因为Activity和Context是继承关系,如图:

类结构
虽然隔了很多代继承,但毕竟是继承,当然可以直接传递Activity对象了(子类的向上转型嘛)。同时,在Activity里自然可以直接用startActivity等等这些成员函数了。

当然,不仅仅Activity了,Service也一样:
Service类结构

ps:这些图都是在官网API文档上截的,英语好的可以直接去看,提高很大的(看得懂的话也就不用看我这个教程了)。

注意两种不同Context

要注意的是,往往说Context有两种:

  • Application Context
  • Activity Context

其实差别就在于生命周期

Application Context是整个Application的Context,app的进程结束了,Application Context才会结束。

而Activity Context的生命周期和你获取这个Context的Activity相关,这个Activity销毁了,这个Context也失效了。

获取Application Context的方式一般就如上文所说的调用getApplicationContext()方法就好。

获取Activity Context就是构造Intent经常用的MyActivity.this。

所以啊,你想,用Intent实现跳转的时候,这个Context只用一次就好,所以直接写MyActivity.this没有问题,但是你要是想在Activity外独立一个Class用Context实现很多很多事,又不确定这个Activity会不会被结束掉,还是乖乖地getApplicationContext()来获取一个“全局的”Context好了。

总结

总的来说,Context很强大也很神奇,你就放心地写你的java代码,有Context的地方就有Android。