这是我参与「第四届青训营 」笔记创作活动的第12天
全局获取Context的技巧
-
有很多地方都需要用到Context,弹出Toast的时候 需要,启动Activity的时候需要,发送广播的时候需要,操作数据库的时候需要,使用通知的时 候需要……
-
而Activity本身就是一个Context对象。但是,当应用程序的架构逐渐开始复杂起来的时候, 很多逻辑代码将脱离Activity类,但此时又恰恰需要使用Context 例如,一个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。
- Android提供了一个Application类,每当应用程序启动的时候,系统就会自动将这个类进行 初始化。而我们可以定制一个自己的Application类,以便于管理程序内一些全局的状态信 息,比如全局Context。 定制一个自己的Application其实并不复杂,首先需要创建一个MyApplication类继承自 Application,代码如下所示:
class MyApplication : Application() {
companion object {
lateinit var context: Context
}
override fun onCreate() {
super.onCreate()
context = applicationContext
}
}
可以看到,MyApplication中的代码非常简单。这里我们在companion object中定义了一 个context变量,然后重写父类的onCreate()方法,并将调用 getApplicationContext()方法得到的返回值赋值给context变量,这样我们就可以以静 态变量的形式获取Context对象了。
- 需要注意的是,将Context设置成静态变量很容易会产生内存泄漏的问题,所以这是一种有风 险的做法。 但是由于这里获取的不是Activity或Service中的Context,而是Application中的Context, 它全局只会存在一份实例,并且在整个应用程序的生命周期内都不会回收,因此是不存在内存 泄漏风险的。那么我们可以使用如下注解,让Android Studio忽略上述警告提示:
class MyApplication : Application() {
companion object {
@SuppressLint("StaticFieldLeak")
lateinit var context: Context
}
...
}
接下来我们还需要告知系统,当程序启动的时候应该初始化MyApplication类,而不是默认的 Application类。这一步也很简单,在AndroidManifest.xml文件的标签下 进行指定就可以了,代码如下所示:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.materialtest">
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
...
</application>
</manifest>·
这样我们就实现了一种全局获取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()