回想这么久以来我们所学的内容,你会发现有很多地方都需要用到 Context,弹出 toast 的时侯需要,启动活动的时侯需要,发送广播的时候需要,操作数据库的时侯需要,使用通知的时候需要……。
或许目前你还没有为得不到 Context 而发愁过,因为我们很多的操作都是在活动中进行的,而活动本身就是一个 Context 对象。但是,当应用程序的架构逐渐开始复杂起来的时候,很多的逻辑代码都将脱离 Activity 类,但此时你又恰恰需要使用 Context,也许这个时候你就会感到有些伤脑筋了。
例如,在第12 章的Kotlin 课堂中,我们编写了一个Toast.kt 文件,并在这里对Toast 的用法进行了封装,代码如下所示:
fun String.showToast(context: Context,duration: Int = Toast.LENGTH_SHORT){
Toast.makeText(context,this,duration).show()
}
fun Int.showToast(context: Context,duration: Int = Toast.LENGTH_SHORT){
Toast.makeText(context,this,duration).show()
}
可以看到,由于Toast 的makeText() 方法要求传入一个Context 的参数,但是当前代码既不在Activity 中,也不在Service 中,是没有办法直接获取Context 对象的。于是这里我们只好给showToast() 方法添加了一个Context 参数,让调用showToast() 方法的人传递一个Context 对象进来。
虽说这也是一种解决方法,但是有点推卸责任的嫌疑,因为我们将获取Context 的任务转移给了 showToast() 方法的调用方,至于调用方能不能得到Context 参数,那就不是我们需要考虑的问题了。
由此可以看出,在某些情况下,获取Context 并非是那么容易的一件事,有时候还是挺伤脑筋的。不过别担心,下面我们就来学习一种技巧,让你在项目的任何地方都能够轻松获取Context 。
Android 提供了一个Application 类,每当应用程序启动的时候,系统就会自动将这个类进行初始化,而我们可以定制一个自己的Application 类,以便于管理程序内一些全局的状态信息,比如全局Context。
定制一个自己的Application 其实并不复杂,首先需要创建一个MyApplication 类继承自Application ,代码如下所示:
class MyApplication:Application(){
companion object {
lateinit var context:Context
}
override fun onCreate() {
super.onCreate()
context = applicationContext
}
}
可以看到,MyApplication 中的代码非常简单。这里我们在compantion object 中定义了一个context 变量,然后重写父类的onCreate() 方法,并将调用getApplicationContext() 方法得到的返回值赋值给context 变量,贝尔杨我们就可以以静态变量的形式获取Context 对象了。
需要注意的是,将Context 设置成静态变量很容易会产生内存泄漏的问题,所以这是一种有风险的做法,因此Android Studio 会给出警告提示。
但是由于这里获取的不是Activity 或 Service 中的Context ,而是Application 中的Context,它全局只会存在一份实例,并且在整个应用程序的生命周期内都不会回收,因此是不存在内存泄漏风险的。那么我们可以使用如下注释,让Android Studio 忽略上述警告提示;
class MyApplication:Application(){
companion object {
@SuppressLint("StaticFieldLeek")
lateinit var context:Context
}
override fun onCreate() {
super.onCreate()
context = applicationContext
}
}
接下来我们还需要告知系统,当程序启动的时候应该初始化MyApplication 类,而不是默认的Application 类。这一步也很简单,在AndroidManifest.xml 文件的
...
这样我们就实现了一种全局获取Context 的机制,之后不管你想在项目的任何地方使用Context,只需要调用一下MyApplication.context 就可以了。
那么接下来我们再对showToast() 方法进行优化,代码如下所示:
fun String.showToast(duration: Int = Toast.LENGTH_SHORT){
Toast.makeText(MyApplication.context,this,duration).show()
}
fun Int.showToast(duration: Int = Toast.LENGTH_SHORT){
Toast.makeText(MyApplication.context,this,duration).show()
}
可以看到,showToast() 方法不需要再通过传递阐述的方式得到Context 对象,而是调用一下MyApplication.context 就可以了。这样 showToast() 方法的用法也得到了进一步的精简,现在只需要使用如下写法就能弹出一段文字提示:
"This is Toast".showToast()
有了这个技巧,你就再也不用为得不到Context 对象而发愁了。