三三要成为安卓糕手
提问:我们现在想传输的数据是一个类怎么办
思路:putExtra方法形参中不能传递自定义类,
①改造我们自己创建的类
②序列化


实现Serializable接口:只用简单实现这个接口就可以了,不用重写什么方法,类在底层被转化成一种字节流的东西,从而达到数据传输的效果
public class User implements Serializable {
private String name;//用户名
private String age;
private int mobile;
public User(String name , String age , int mobile){
this.name = name;
this.age = age;
this.mobile = mobile;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public int getMobile() {
return mobile;
}
public void setMobile(int mobile) {
this.mobile = mobile;
}
} else if (id == R.id.btn_second6) {
Intent intent = new Intent(this, SerialActivity.class);
User user = new User("三三", "18", 123456);
intent.putExtra("key_user", user);
startActivity(intent);
} //接收类数据
Intent intent = getIntent();
User user = (User) intent.getSerializableExtra("key_user");
if (user != null) {
String name = user.getName();
String age = user.getAge();
int mobile = user.getMobile();
Log.i(TAG, "onCreate: name = " + name);
Log.i(TAG, "onCreate: age = " + age);
Log.i(TAG, "onCreate: mobile = " + mobile);
} else {
Log.e(TAG, "onCreate: user is null");
}
双参数的,需要版本在29以上,为了兼顾老版本,优先使用单参数方式

getSerializableExtra(String name, Class<T> clazz) :这是 Android API 29 引入的方法,它在获取数据的同时,通过传入目标类型的 Class 对象,直接返回指定类型的数据;比如这段代码
Intent intent = getIntent();
MySerializableClass myObj = intent.getSerializableExtra("key", MySerializableClass.class);
if (myObj != null) {
// 处理 myObj
}getSerializableExtra(String name) :返回一个 Serializable 类型的对象。获取到数据后,需要强制将其转换为实际需要的类型。
想要让数据传输中性能更好,Android中专门诞生了一个接口Parcelable(包是安卓下的)
顾名思义parcelable 翻译为 “可打包的” (用于跨进程传输)
public class Student implements Parcelable {
private static final String TAG = "Student";
private String name;//用户名
private String age;//年龄
private int mobile;//手机号
public Student(String name, String age, int mobile) {
this.name = name;
this.age = age;
this.mobile = mobile;
}
public Student(Parcel parcel){
name = parcel.readString();
age = parcel.readString();
mobile = parcel.readInt();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public int getMobile() {
return mobile;
}
public void setMobile(int mobile) {
this.mobile = mobile;
}
@Override
public int describeContents() {
return 0;
}
/**
* 打包操作
*/
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(age);
dest.writeInt(mobile);
Log.i(TAG, "writeToParcel: ");
}
/**
* 拆包操作
*/
public static final Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel source) {
Log.i(TAG, "createFromParcel: source" + source);
return new Student(source);
}
@Override
public Student[] newArray(int size) {
return new Student[0];
}
};
}对象序列化的核心方法,将当前对象的所有成员变量写入到 Parcel 对象中,后续可以通过对应的 CREATOR 从 Parcel 中恢复对象
参数dest 是 destination 的缩写,意为 “目的地”。传递数据的时候做一个打包的工作
/**
* 打包操作
*/
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(age);
dest.writeInt(mobile);
Log.i(TAG, "writeToParcel: ");
}返回的是一个Student对象,那就先读取三个变量,在作为构造方法里的参数进行传参,但是不行因为这是静态方法
CREATOR 是 静态内部实现(public static final Creator<Student> CREATOR ),方法内部只能访问静态成员变量

Parcelable 的 “约定玩法”官方 / 社区习惯上,会给 Parcelable 类专门写一个 protected 或 public 的构造函数,参数是 Parcel,专门用来接收数据,用于反序列化,为对象的成员变量赋值。
public Student(Parcel parcel){
name = parcel.readString();
age = parcel.readString();
mobile = parcel.readInt();
}public static final Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel source) {
Log.i(TAG, "createFromParcel: source" + source);
return new Student(source);
}
@Override
public Student[] newArray(int size) {
return new Student[0];
}
};createFromParcel(Parcel source) 方法作用:从序列化后的 Parcel 对象中读取数据
参数 source:是之前通过 writeToParcel() 写入数据的 Parcel 对象(可以理解为 “数据源”)。
newArray(int size) 方法Student 数组,用于批量反序列化时使用(例如从 Parcel 中读取多个 Student 对象时)。
参数 size:需要创建的数组长度。返回值写成 new Student[size]更合适
else if (id == R.id.btn_second7) {
try {
Intent intent = new Intent(this, ParcelActivity.class);
Student sansan = new Student("Sansan", "18", 12345);
intent.putExtra("key_student", sansan);
startActivity(intent);
} catch (Exception e) {
Log.e(TAG, "跳转ParcelActivity失败: " + e.getMessage(), e);
}
}public class ParcelActivity extends AppCompatActivity {
private static final String TAG = "ParcelActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_parcel);
Intent intent = getIntent();//注意这段代码,不是new Intent();
Student student = intent.getParcelableExtra("key_student");
String name = student.getName();
String age = student.getAge();
int mobile = student.getMobile();
Log.i(TAG, "onCreate: name = " + name);
Log.i(TAG, "onCreate: age = " + age);
Log.i(TAG, "onCreate: mobile" + mobile);
}
}在某个版本之前也是被限定的,用兼容性更好的单个参数即可

通过日志可以看见通过parclable传过来的数据

Parcelable中很多代码是规范化和统一化的,所以使用一个插件能减少我们的工作量,直接生成模版


两种传递类数据的方式,前者silizeable简单,后者难但是性能好