使用Intent传递数据
在启动活动时传递数据的思路很简单,Intent 中提供了一系列 putExtra()方法的重载,可 以把我们想要传递的数据暂存在 Intent 中,启动了另一个活动后,只需要把这些数据再从 Intent 中取出就可以了。
Intent传递基本数据类型
向后一个Activity传递数据
通过 putExtra()方法传递 了一个字符串。注意这里 putExtra()方法接收两个参数,第一个参数是键,用于后面从 Intent 中取值,第二个参数才是真正要传递的数据。
String data = "Hello SecondActivity";
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("extra_data", data);
startActivity(intent);
可以通过 getIntent()方法获取到用于启动 SecondActivity 的 Intent,然后调用 getStringExtra()方法,传入相应的键值,就可以得到传递的数据了。这里由于我们传递的是 字符串,所以使用 getStringExtra()方法来获取传递的数据,如果传递的是整型数据,则使用 getIntExtra()方法,传递的是布尔型数据,则使用 getBooleanExtra()方法,以此类推。
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
向前一个Activity返回数据
Activity中有一个startActivityForResult() 方法也是用于启动活动的,但这个方法期望在活动销毁的时候能够返回一个结果给上一个活动。startActivityForResult()方法接收两个参数,第一个参数还是 Intent,第二个参数是请求码,用于在之后的回调中判断数据的来源。
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivityForResult(intent, 1);
返回数据到前一个Activity时也是通过Intent,只不过这个 Intent 仅仅是用于传递数据而已, 它没有指定任何的“意图”。紧接着把要传递的数据存放在 Intent 中,然后调用了 setResult() 方法。这个方法非常重要,是专门用于向上一个活动返回数据的。setResult()方法接收两个 参数,第一个参数用于向上一个活动返回处理结果,一般只使用 RESULT_OK 或 RESULT_CANCELED 这两个值,第二个参数则是把带有数据的 Intent 传递回去,然后调用 了 finish()方法来销毁当前活动。
Intent intent = new Intent();
intent.putExtra("data_return", "Hello FirstActivity");
setResult(RESULT_OK, intent);
finish();
由于我们是使用 startActivityForResult()方法来启动 SecondActivity 的,在 SecondActivity 被销毁之后会回调上一个活动的 onActivityResult()方法,因此我们需要在 FirstActivity 中重 写这个方法来得到返回的数据。onActivityResult()方法带有三个参数,第一个参数 requestCode,即我们在启动活动时传 入的请求码。第二个参数 resultCode,即我们在返回数据时传入的处理结果。第三个参数 data, 即携带着返回数据的 Intent。由于在一个活动中有可能调用 startActivityForResult()方法去启 动很多不同的活动,每一个活动返回的数据都会回调到 onActivityResult()这个方法中,因此 我们首先要做的就是通过检查 requestCode 的值来判断数据来源。确定数据是从SecondActivity 返回的之后,我们再通过 resultCode 的值来判断处理结果是否成功。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case 1:
if (resultCode == RESULT_OK) {
String returnedData = data.getStringExtra("data_return");
Log.d("FirstActivity", returnedData);
}
break;
default:
} }
Intent传递对象
使用 Intent 来传递对象通常有两种实现方式,Serializable 和 Parcelable。
Serializable
为什么要将对象序列化?
1、永久性保存对象,保存对象的字节序列到本地文件中;
2、用过序列化对象在网络中传递对象;
3、通过序列化对象在进程间传递对象。
Serializable的作用是将数据对象存入字节流当中,在需要时重新生成对象,主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等。
implements Serializable接口的的作用就是给对象打了一个标记,系统会自动将其序列化。
要传递的对象类:
public class Person implements Serializable {
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;
}
}
第一个Activity
Person person = new Person();
person.setAge(18);
person.setName("Nick");
Intent intent = new Intent(this,Second.class);
intent.putExtra("person data",person);
startActivity(intent);
第二个Activity
Intent intent = getIntent();
Person person = (Person) intent.getSerializableExtra("person data");
TextView textView = (TextView)findViewById(R.id.textView);
textView.setText("name :" + person.getName() + " age:"+person.getAge());
Parcelable
为什么要实现Parfcelable接口来实现在Intent中传递对象?
- 在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable类。
Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
注意:Parcelable不能使用在将数据存储在磁盘上的情况,因为Parcelable不能很好的保存数据的持续性在外界有变化的情况下。因此在这种情况下,建议使用Serializable
Parcel类
就应用程序而言,在常使用Parcel类的场景就是在Activity间传递数据。在Activity间使用Intent传递数据的时候,可以通过Parcelable机制传递复杂的对象。
Parcelable 方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都 是 Intent 所支持的数据类型,这样也就实现传递对象的功能了。
实现Parcel类步骤:
- 实现describeContents方法。内容接口描述,默认返回0就可以;
- 实现writeToParcel方法。将传递的数据打包到Parcel容器中;
- 该实体类必须添加一个常量CREATOR(名字大小写都不能使其他的),该常量必须实现Parcelable的内部接口:Parcelable.Creator,并实现该接口中的两个方法。
public class Person implements Parcelable{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
//该方法将类的数据写入外部提供的Parcel中.即打包需要传递的数据到Parcel容器保存,以便从parcel容器获取数据
dest.writeString(name);
dest.writeInt(age);
}
public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>(){
@Override
public Person createFromParcel(Parcel source) {
//从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层。
Person person = new Person();
person.name = source.readString();
person.age = source.readInt();
return person;
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
}
简化Parcel操作
如果你使用android Studio可以通过安装android-parcelable-intellij-plugin插件,或者自己配置模板进行操作。parceler
除了上面的操作,还有大量的第三方库来简化Parcelable操作。当然使用这些库也许会降低Parcelable的性能。Parceler就是这样一个库。Parceler使用非常简单,在定义Model时用@Parcel进行注解,在传递数据的时候使用Parcels的wrap方法来包装成一个Parcelable对象。获取数据时用Parcels的unwrap方法来获取对象。
使用Parceler库
//引入Parceler库
compile "org.parceler:parceler-api:1.0.4"
annotationProcessor "org.parceler:parceler:1.0.4"
//用@Parcel注解model类
@Parcel
public class people{
String name;
int age;
public people(){ /*Required empty bean constructor*/ }
public people(int age, String name) {
this.age = age;
this.name = name;
}
public String getName() { return name; }
public int getAge() { return age; }
}
//把model类打包到parcelable中
Parcelable parcel = Parcels.wrap(people);
bundle.putParcelable("abc",parcel);
//把model类从parcelable中取出
Parcelable parcelable = bundle.getParcelable("abc");
people people = Parcels.unwrap(parcelable);
使用全局变量传递数据
Application和Activity,Service一样是android框架的一个系统组件,当android程序启动时系统会创建一个 application对象,用来存储系统的一些信息。通常我们是不需要指定一个Application的,这时系统会自动帮我们创建,如果需要创建自己 的Application,也很简单创建一个类继承 Application并在manifest的application标签中进行注册(只需要给Application标签增加个name属性把自己的 Application的名字定入即可)。
<application
android:name=".MyApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>
android系统会为每个程序运行时创建一个Application类的对象且仅创建一个,所以Application可以说是单例 (singleton)模式的一个类.且application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期。因为它是全局 的单例的,所以在不同的Activity,Service中获得的对象都是同一个对象。所以通过Application来进行一些,数据传递,数据共享 等,数据缓存等操作。
基本思路是这样的。在Application中创建一个HashMap<String,Object>
,以字符串为索引,Object为value这样我们的HashMap就可以存储任何类型的对象了。在Activity A中把需要传递的对象放入这个HashMap,然后通过Intent或者其它途经再把这人索引的字符串传递给Activity B ,Activity B 就可以根据这个字符串在HashMap中取出这个对象了。只要再向下转个型 ,就实现了对象的传递。
public class MyApp extends Application{
private Map<String,Object> globalData;
@Override
public void onCreate() {
super.onCreate();
globalData = new HashMap<String, Object>();
}
public Object getGlobalData(String key){
return globalData.get(key);
}
public void addGlobalData(String key, Object value){
globalData.put(key, value);
}
public void removeGlobalData(String key)
{
globalData.remove(key);
}
@Override
public void onTerminate() {
super.onTerminate();
globalData.clear();
}
}
记得数据传递完成之后,把存放在application的HashMap中的数据remove掉,以免发生内存的泄漏。
FirstActivity:
Intent intent = new Intent(this,Main2Activity.class);
String userCode = "nick18";
intent.putExtra("main",userCode);
MyApp myApp = (MyApp)getApplication();
User user = new User();
user.age = 18;
user.name = "nick";
myApp.addGlobalData(userCode,user);
startActivity(intent);
SecondActivity:
Intent intent = getIntent();
String userCode = intent.getStringExtra("main");
MyApp myApp = (MyApp) getApplication();
User user = (User) myApp.getGlobalData(userCode);
if (user != null) {
Log.d("t", "name :" + user.name + " age :" + user.age);
myApp.removeGlobalData(userCode);
}