Intent就是意图的意思,分两种:显式的(Explicit intent)和隐式的(Implicit intent)。Intent还是很有用的一个好东西,可以帮我们启动活动、发送广播、启动服务等等。但是它并不是这么简单,它还能耍一耍传递数据的花活,除了使用函数直接传递数据,还有序列化传递数据的方法。
基本用法
显式 Intent
按名称(完全限定类名)指定要启动的组件。 通常,知道要启动的 Activity 或服务的类名时,使用显式 Intent 来启动组件。例如,启动新 Activity 以响应用户操作,或者启动服务以在后台下载文件。
显示调用本质上都是设置Component,从而指定Activity类。常见的用法有:
//这是最常见的了
val intent = Intent(MainActivity@this, SecondActivity::class.java)
startActivity(intent);
//这个比较能看出本质用法
val componentName = ComponentName(MainActivity@this, SecondActivity::class.java)
val intentNewActivity = Intent()
intentNewActivity.component = componentName
startActivity(intent)
//第三种方法
val intentNewActivity = Intent()
intentNewActivity.setClass(MainActivity@this, SecondActivity::class.java)
startActivity(intent)
隐式 Intent
不会指定特定的组件,而是设置Action、Data、Category,让系统来筛选出合适的Activity,从而允许其他应用中的组件来处理它,这会降低程序的耦合度,但效率更低。例如,如需在地图上向用户显示位置,则可以使用隐式 Intent,请求另一具有此功能的应用在地图上显示指定的位置。
//首先,要在AndroidManifest.xml中的application标签中设置如下
//在kotlin文件中编写代码如下
val intentNewActivity = Intent("android.intent.action.SECOND")
传递简单的数据
比如说,我们可以在某一个活动中定义这样一个intent:
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("a string", "hello world");
intent.putExtra("a int", 123);
startActivity(intent);
然后,我们可以在第二个活动这样获取上例中的数据:
getIntent().getStringExtra("a string");
getIntent().getIntExtra("a int", 0);
可以看到,数据传递还是很简单的,也很容易理解,需要说明的时,putExtra函数的参数是以键值对的方式给出的,getIntExtra函数的第二个参数是默认值,也就是不能成功获取数据的时候的函数返回值,可以随便写啦。但是嘞,这种方法传递的数据类型还是很有限的,当我么需要传递自定义的数据类型的时候,就会很捉急!燃鹅不用担心,我们还有更多的技巧用来传递数据。
Serializable方式
Serializable即序列化,意思就是将一个对象转换成可存储或者可传输的状态。具体的实现方法是让一个类去实现Serializable这个接口(import java.io.Serializable)。
//在某一个Activity中定义一个类
class Person : Serializable{
var name: String = "Baiyuqing"
var age: Int = 26
}
//在某个跳转函数中传递
val intent = Intent()
intent.setClass(MainActivity@this, SecondActivity::class.java)
val person = Person()
intent.putExtra("person data", person)
startActivity(intent)
数据的获取也就不一样咯:
val person = intent.getSerializableExtra("person data") as Person
val name:String? = person.name
val age:Int? = person.age
这里调用了getSerializableExtra()函数来获取通过参数传递过来的序列化对象,接着再将它向下转型为Person对象,这样我们就成功实现了利用intent来传递对象的功能啦!
不过,这种方法实际上是使用反射做的,所以效率会略低,并且它会在序列化的过程中,会创建很多临时变量,所以更容易触发GC(垃圾收集)。
Parcelable方式
Parcelable的实现原理是将一个完整的对象进行分解,而分解之后的每一部分都是Intent可以传递的数据类型。
代码实现:
public class Person implements Parcelable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel test, int flags) {
test.writeString(name);
test.writeInt(age);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
@Override
public Person createFromParcel(Parcel source) {
Person person = new Person();
person.name = source.readString(); //读取name
person.age = source.readInt(); //读取age
return person;
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
}
复杂……好烦……是不是……
但是!这种方法的效率会比前者更高,因为它规则确定、没有将整个对象序列化。烦的是 Parcelable 需要开发者自己去实现序列化的规则。
但是!
在新版的 Kotlin(1.1.4)插件中,已经自动包含了一个自动 Parcelable 实现生成器。简单来说,只需要在主函数中,声明序列化的属性,即添加一个 @Parcelize
注解,它将自动为我们创建 writeToParcel() 和 createFromParcel()。
首先,也是实现接口,然后重写了两个函数describeContents()和writeToParcel()。尤其是第二个函数,要在这里面将类的各个字段一一写出。我们还必须在Person类中提供一个名为CREATE的常量。数据的加载方式不变,具体的获取数据的方法基本一致,只不过换了个名字:
Person person = (Person) getIntent().getParcelableExtra("person data");