全局获取context

前提:或许目前你还没有为得不到Context而发愁过,因为我们很多的操作是在Activity中进行的,而Activity本身就是一个Context对象。但是,当应用程序的架构逐渐开始复杂起来的时候,很多逻辑代码将脱离Activity类,但此时你又恰恰需要使用Context,也许这个时候你就会感到有些伤脑筋了。
解决:Android提供了一个Application类,每当应用程序启动的时候,系统就会自动将这个类进行初始化。而我们可以定制一个自己的Application类,以便于管理程序内一些全局的状态信息,比如全局Context。

1
2
3
4
5
6
7
8
9
class MyApplication : Application() {
companion object {
lateinit var context: Context
}
override fun onCreate() {
super.onCreate()
context = applicationContext
}
}

这样我们就可以以静态变量的形式获取Context对象了。需要注意的是,将Context设置成静态变量很容易会产生内存泄漏的问题,所以这是一种有风险的做法.
但是由于这里获取的不是Activity或Service中的Context,而是Application中的Context,它全局只会存在一份实例,并且在整个应用程序的生命周期内都不会回收,因此是不存在内存泄漏风险的。
程序启动的时候应该初始化MyApplication类,在AndroidManifest.xml文件的<application>标签下进行指定android:name=".MyApplication".

使用Intent传递对象

我们用的一直都是一些基础的数据类型如Int,String之类的。而不能传递我们自定义的对象。因此我们需要使用到序列化

Serializable方式

让你的类实现Serializable接口,把对象放入intent时,就是普通的方法intent.putExtra("person_data", person)
但是取出时需要使用特定的获取方法val person = intent.getSerializableExtra("person_data") as Person,这样子才能获得序列化后的对象。注意,虽然你传递的对象内的值都一摸一样,但是这两个对象不是同一个对象。

Parcelable方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Person : Parcelable {
var name = ""
var age = 0
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name) // 写出name
parcel.writeInt(age) // 写出age
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Person> {
override fun createFromParcel(parcel: Parcel): Person {
val person = Person()
person.name = parcel.readString() ?: "" // 读取name
person.age = parcel.readInt() // 读取age
return person
}
override fun newArray(size: Int): Array<Person?> {
return arrayOfNulls(size)
}
}
}

这种方式更加复杂,他需要实现Parcelable接口,然后重写他的describeContents()和writeToParcel()这两个方法。其中describeContents()方法直接返回0就可以了。而对于writeToParcel需要对他的每个属性使用write***方法,如上所示。
除此之外我们还必须在Person类中提供一个名为CREATOR的匿名类实现。接着需要重写createFromParcel()和newArray()这两个方法,在createFromParcel()方法中,我们要创建一个Person对象进行返回,并读取刚才写出的name和age字段。其中name和age都是调用Parcel的readXxx()方法读取到的,注意这里读取的顺序一定要和刚才写出的顺序完全相同。而newArray()方法中的实现就简单多了,只需要调用arrayOfNulls()方法,并使用参数中传入的size作为数组大小,创建一个空的Person数组即可

然后传入intent还是一样的,但是取出时需要使用另外的方法val person =intent.getParcelableExtra("person_data") as Person
但是这种实现方法过于复杂,所以kotlin实现了简单的语法,只要加上@Parcelize注解即可。前提是所有数据必须封装在对象的主构造函数中,也就是简单的写为data class。
对比一下,Serializable的方式较为简单,但由于会把整个对象进行序列化,因此效率会比Parcelable方式低一些,所以在通常情况下,还是更加推荐使用Parcelable的方式来实现Intent传递对象的功能。

定制自己的日志工具