一、向下一个活动传递数据
前面我们在介绍Intent的时候有说过,我们可以利用Intent在不同组件之间传递数据,接下来这篇文章就是记录如何利用Intent在不同Activity之间传递简单数据、传递数据包、传递值对象以及返回数据给上一个活动的知识。
1. 传递简单数据
主要方法:
①putExtra(String name,String value);
putExtra(String name,int value);
(putExtra()有多种重载方法,这里不一一列举)
第一个参数是是键(即要传递数据的名字);
第二个参数是要传递的数据(可以使String型、int型、double型等等)。
②getIntent();
③getStringExtra(String name);
getInExtra(String name);
参数是前面的键,也即是要传递数据的名字。
思路
①用Intent提供的一系列putExtra()方法(各种重载方法)将要传递的数据暂存在Intent中。
在MainActivity中,
case R.id.button1:
intent = new Intent(MainActivity.this,Aty1.class);
intent.putExtra("data_aty1","这是从MainActivity传入Aty1的数据:"+data);
startActivity(intent);
break;
②在下一个活动中用Intent提供的getStringExtra()方法将传递的数据取出。
在Aty1的onCreate()方法中:
tv_aty1 = (TextView)findViewById(R.id.textView_aty1);
Intent intent = getIntent();
String tempData = intent.getStringExtra("data_aty1");
tv_aty1.setText(tempData);
效果图:
2. 传递数据包
主要方法:
①Bundle();
方法中存储数据包的方法:
putString(String name,String value);
//存储字符串在Bundle包中
putInt(String name,int value);
//存储整型数据在Bundle包中
等(还可以有float型,double型等,就不一一列出来了)
②putExtras(Bundle extras);
参数extras为数据包Bundle的实例
或
putExtra(String name,Bundle value);
name是数据包的名字,方便传递进其他活动中取出;
value为数据包Bundle的实例。
③getIntent();
④Intent中提供有:
getExtras();
方法
getBundleExtra(String name);
方法
name是②种数据包的名字。
⑤取出数据包中的具体属性:
getString(String name);
getInt(String name);
等等
思路:
①将一系列的数据(包括字符串、整型、布尔型等等)整合在Bundle包中(利用putString()、putInt()等方法),用Intent中的putExtras()或者putExtra()方法传递给其他活动。
在MainActivity中,
case R.id.button2:
intent = new Intent(MainActivity.this,Aty2.class);
Bundle bundle = new Bundle();
bundle.putString("name",data);
bundle.putInt("age",18);
intent.putExtras(bundle);
startActivity(intent);
break;
②在下一个活动中,利用getExtras()或getBundleExtra()方法将Bundle包传递过来,然后利用Bundle中的getString()等方法将数据取出来。
在Aty2的onCreate()方法中:
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
et_aty2.setText(String.format("姓名:%s 年龄:%d",bundle.getString("name"),bundle.getInt("age") ));
效果图:
假如sex在Bundle包中不存在,可以写成
et_aty2.setText(String.format("姓名:%s 年龄:%d 性别:%s",bundle.getString("name"),bundle.getInt("age"),bundle.getString("sex","女") ));
效果图:
假如sex在Bundle包中存在且赋值为”男”,此时获取数据中还是写成
bundle.getString("sex","女") ));
,会发生什么呢?可以动手试试。
3. 传递值对象
值对象:自定义的,有数据类型的对象。
有两种序列化对象的接口可以用于传递值对象:
①java.io.Serializable
②android.os.Parcelable
接下来分别介绍一下这两种接口是如何传递值对象的。
(1) Serializable序列化接口
这是java语言内置的用于序列化对象的接口,只需要implements Serializable,其余的系统会自动处理,因此效率会比较低。
①新建一个java类——User.java
(implrments Serialiable
)
import java.io.Serializable;
public class User implements Serializable{
private String name;
private int age;
//两个参数的构造方法
public User(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getInt(){
return age;
}
}
②用putExtra()
方法将User中的数据保存在MainActivity中
case R.id.button3:
intent = new Intent(MainActivity.this,Aty3.class);
User user = new User(data,19);
intent.putExtra("user",user);
startActivity(intent);
break;
③在Aty3中用getSerialiableExtra()
方法将数据取出
Intent intent = getIntent();
User user = (User)intent.getSerializableExtra("user");
tv_aty3.setText(String.format("名字:%s 年龄:%d",user.getName(),user.getInt()));
效果图:
(2) Parcelable序列化接口
这是Android平台提供的用于序列化对象的接口,使用该接口需要重写一系列与数据有关的方法,因此效率较Serialiable接口高。
①新建一个java类——User2.java
(implrments Parcelable
)
import android.os.Parcel;
import android.os.Parcelable;
public class User2 implements Parcelable {
private String name;
private int age;
//两个参数的构造方法
public User2(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
②如果只是这样写的话,系统会报错
③因此我们要重写一些方法,此时系统会给出提示:
因此我们要重写describeContents()
方法和writeToParcel()
方法
a).describeContents()
这个方法只需要重写,暂时不用管。
@Override
public int describeContents() {
return 0;
}
b).writeToParcel()
我们要在这个方法里向目标Parcel写数据,因为Parcelable接口没有全自动地序列化机制,它需要我们手动写。
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(getName());
parcel.writeInt(getAge());
}
④除此之外,我们还需要重写如下方法去读取数据。
public static final Creator<User2> CREATOR = new Creator<User2>() {
@Override
public User2 createFromParcel(Parcel in) {
return new User2(in.readString(),in.readInt());
}
@Override
public User2[] newArray(int size) {
return new User2[size];
}
};
⑤最后我们在Aty4里调用getParcelableExtra()
方法接收数据。
Intent intent = getIntent();
User2 user2 = intent.getParcelableExtra("user2");
tv_aty4.setText(String.format("姓名:%s 年龄:%d ",user2.getName(),user2.getAge()));
效果图:
注:这两种接口方式我也没有理解的很深奥,只是将自己的理解记录下来,如果有错误的话,可以小小地喷一下,最重要的是希望能指出我理解的不正确的地方。
二、返回数据给上一个活动
前面我们讲了向下一个活动传递数据,接下来我们就讲讲把数据返回给上一个活动。
相关方法:
①startActivityForResult(Intent intent,int requestCode);
该方法跟startActivity()
方法一样,也是用于启动活动的,但这个方法期望在活动销毁的时候能够返回一个结果给上一个活动。
参数1还是Intent;
参数2是请求码,用于在之后的回调中判断数据的来源。
②setResult(int resultCode,Intent data);
这个方法是专门用于向上一个活动返回数据的。
参数1用于向上一个活动返回处理结果,一般只使用RESULT_OK或RESULT_CANCELED这两个值;
参数2则把带有数据的Intent传递回去。
①在MainActivity中,调用startActivityForResult()
方法启动Aty5。
case R.id.button5:
intent = new Intent(MainActivity.this,Aty5.class);
startActivityForResult(intent,1);
break;
②在Aty5中注册一个按钮,在点击事件中添加返回数据的逻辑并返回主页面。
Intent intent = new Intent();
String data = et_aty5.getText().toString();
intent.putExtra("data_aty5",data);
setResult(RESULT_OK,intent);
finish();
③由于我们是使用startActivityForResult()
方法来启动Aty5的,在Aty5被销毁之后会回调上一个活动的onActivityResult()
方法,因此我们需要在MainActivity中重写这个方法来得到返回数据。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case 1:
if(resultCode == RESULT_OK){
String str = data.getStringExtra("data_aty5");
tv_atymain.setText(str);
}
break;
default:
break;
}
}
效果图:
我们还可以通过在Aty5中重写onBackPressed()
方法,使按下Back键之后把数据返回。这个大家可以自己试试