Activity之间传递参数(使用Parcelable和Serializable接口传递复杂类型)

xiaoxiao2021-02-28  81

传递基本数据类型参数

使用Intent的putExtra和get***Extra方法传递参数

存参数: 使用Intent的putExtra方法,以键值对的形式存入参数 可以使用多次put存入多个参数

取参数: 使用getIntent()方法获取到Intent对象的实例 通过get***Extra(getStringExtra等),形参指定key获得value,也可以使用getExtras().getSting() (Int等也行) 指定key获得value。

此方法较为简单,不进行代码列举了


使用Bundle传递参数

使用Bundle可以将多个基本类型数据(也可以传自定义类对象,需要实现Parcelable接口)以键值对的形式打包入Bundle中,在Activity传递。

存参数: 在使用Intent进行Activity跳转时,创建Bundle实例

通过put函数(putString和putInt等,通过键值对存储数据)存入

使用intent.putExtras(bundle)将bundle和intent绑定。

Bundle也可以使用键值对的方式和Intent进行绑定,使用Intent的putExtra()函数,

在另一个Activity中使用getBundleExtra()函数通过传入键取得Bundle的实例

Intent intent = new Intent(MainActivity.this, SecondActivity.class); Bundle bundle = new Bundle(); bundle.putString("name","W"); bundle.putInt("age",20); //intent.putExtras(bundle);//此方法也可行 intent.putExtra("text", bundle); intent.putExtra("id", D_BUNDLE);//D_BUNDLE(自定义静态整型)是用于判断是以何种方式传递数据,最后会给出完整代码,既会明白 startActivity(intent);

取参数: 在目标Activity中通过getIntent()获取到Intent的实例

通过Intent对象的getExtras()获取到Bundle的实例

在通过Bundle对象的get方法(getString, getInt等),形参传入键,得到值

此外get方法有到两个参数的重载,第一个参数是键,第二个参数是默认值,如果没有获取到值,使用第二个参数为返回值。

Intent intent = getIntent(); Bundle bundle = intent.getBundleExtra("text"); String name = bundle.getString("name"); int age = bundle.getInt("age"); String des = bundle.getString("des","No describe");//若没有值,给定一个默认值 textView.setText("Name is " + name + ",age is " + age + ",describe is " + des);

传递自定义复杂类型参数(自定义类)

使用Parcelable接口实现传递自定义类对象

Parcelable作用:定义了将数据写入Parcel和从Parcel读取数据的接口。如果一个类需要封装到消息中,则这个类必须实现Parcelable接口,实现后该类就是“可打包的”。

describeContents()方法:内容接口描述,默认return 0 即可

writeToParcel(Parcel dest, int flags)方法:将数据写入外部提供的Parcel中,即打包需要传递的数据到Parcel中,其中打包的顺序需要按照数据的声明顺序,乱序会出现数据读取错误。

静态Parcelable.Creator接口:接口有两个方法 createFromParcel(Parcel in)方法:从Parcel容器中读取数据,封装到Parcelable中返回到逻辑层

newArray(int size):创建一个类型为T,长度为size的数组,return new T[size];即可。方法是供外部类反序列化本类数组使用。

这里重点强调一下writeToParcel方法和静态Parcelable.Creator接口的createFromParcel方法,前者的向Parcel容器写入数据和后者从Parcel容器读取的顺序必须和成员变量声明顺序一致,否则会读取数据出错

package com.android.wrf_mac.activity_deliver; import android.os.Parcel; import android.os.Parcelable; /** * Created by wrf_mac on 2017/7/7. */ public class Book implements Parcelable { private String bookName; private String author; private int price; public void setBookName(String bookName) { this.bookName = bookName; } public void setAuthor(String author) { this.author = author; } public void setPrice(int price) { this.price = price; } public String getBookName() { return bookName; } public String getAuthor() { return author; } public int getPrice() { return price; } // 1.必须实现Parcelable.Creator接口,否则在获取Person数据的时候,会报错,如下: // 2.这个接口实现了从Parcel容器读取Book数据,并返回Book对象给逻辑层使用 // 3.实现Parcelable.Creator接口对象名必须为CREATOR,不然会报错 // 4.在读取Parcel容器里的数据时,必须按成员变量声明的顺序读取数据,不然会出现获取数据出错 public static final Creator<Book> CREATOR = new Creator<Book>() { /** * TODO:安装成员变量的声明顺序读取数据,然后存入Book对象,返回Book对象给逻辑层用 * @param in * @return */ @Override public Book createFromParcel(Parcel in) { Book book = new Book(); book.setBookName(in.readString()); book.setAuthor(in.readString()); book.setPrice(in.readInt()); return book; } //供外部类反序列化本类数组使用 @Override public Book[] newArray(int size) { return new Book[size]; } }; //内容接口描述,默认返回0即刻 @Override public int describeContents() { return 0; } /** * TODO:按照声明顺序打包数据到Parcel对象中,既将数据打包到Parcel容器中 * TODO:使用write***方法打包数据 * @param parcel * @param i */ @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeString(bookName); parcel.writeString(author); parcel.writeInt(price); } }

使用Serializable接口实现传递自定义类对象

此接口时java.io接口,使用简单,但效率较Parcelable接口慢许多。

将需要传递的类实现Serializable接口,该接口只是一个标识接口,没有任何接口方法。

只需在类中指定serialVersionUID的值,该值可以任意指定一个值

(注:这里的serialVersionUID的值是手动指定,如果没有指定,则由编译器根据当前类的结构自动去生成它的hash值,这样序列化和反序列化时两者的serialVersionUID是相同的,因此可以正常进行反序列化。如果不手动指定serialVersionUID的值,反序列化时当前类有所改变,比如增加或者删除了某些成员变量,那么系统就会重新计算当前类的hash值并把它赋值给serialVersionUID,这个时候当前类的serialVersionUID就和序列化的数据中的serialVersionUID不一致,于是反序列化失败。)这段话是从前辈借鉴,慢慢品味吧

具体实现只需在原有类代码加入一行代码

static final long serialVersionUID = 3453521L;

实现后就可以直接使用Intent的put和get函数传递该类对象了(具体代码请看后面完整代码)


使用Intent传递参数并从第二个Activity返回参数到第一个Activity

在第一个Activity使用startActivityForResult()启动另外一个Activity:带两个参数,第一个是Intent实例对象,第二个是请求码(int类型)

需要在第一个Activity中重写onActivityResult函数:第一个参数是请求码,第二个是返回码,第三个是Intent实例(携带数据) 此方法处理返回Activity后的逻辑

以下为onActivityResult函数:

protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode){ case TO_SA_CODE: if (resultCode == SecondActivity.BACK_MA_CODE){ textView.setText(data.getStringExtra("who")); } } }

在第二个Activity使用Intent存储数据,使用setResult()发送数据,该方法有两个参数,第一个参数是Intent类型,第二个参数是返回码。(这里使用一个Button返回数据)

back.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(); intent.putExtra("who", "I`m SecondActivity"); setResult(BACK_MA_CODE, intent); finish(); } });

以下给出项目完整代码: 程序截图:

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="使用Bundle传递基础数据类型数据" android:textAllCaps="false"/> <Button android:id="@+id/button2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="使用Parcelable接口传对象数据" android:textAllCaps="false" /> <Button android:id="@+id/button3" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="使用Serializable接口传对象数据" android:textAllCaps="false" /> <Button android:id="@+id/button4" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="使用startActivityForResult传参带返回值" android:textAllCaps="false" /> <TextView android:id="@+id/tex_view_result" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center"/> </LinearLayout>

MainActivity.java:

package com.android.wrf_mac.activity_deliver; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener { public static final int D_BUNDLE = 1; public static final int D_PARCELABLE = 2; public static final int D_SERIALIZABLE = 3; public static final int D_RESULT = 4; public static final int TO_SA_CODE = 100; private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.button1).setOnClickListener(this); findViewById(R.id.button2).setOnClickListener(this); findViewById(R.id.button3).setOnClickListener(this); findViewById(R.id.button4).setOnClickListener(this); textView = (TextView) findViewById(R.id.tex_view_result); } @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, SecondActivity.class); switch (view.getId()){ case R.id.button1: //使用Bundle存入参数 Bundle bundle = new Bundle(); bundle.putString("name","W"); bundle.putInt("age",20); //intent.putExtras(bundle); intent.putExtra("text", bundle); intent.putExtra("id", D_BUNDLE); startActivity(intent); break; case R.id.button2: Book book = new Book(); book.setBookName("第一行代码"); book.setAuthor("郭霖"); book.setPrice(59); intent.putExtra("book", book); intent.putExtra("id", D_PARCELABLE); startActivity(intent); break; case R.id.button3: Person person = new Person(); person.setName("wrf"); person.setAge(21); person.setAddress("Beijing"); intent.putExtra("person", person); intent.putExtra("id", D_SERIALIZABLE); startActivity(intent); break; case R.id.button4: intent.putExtra("who", "I`m MainActivity"); intent.putExtra("id", D_RESULT); startActivityForResult(intent, TO_SA_CODE); break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode){ case TO_SA_CODE: if (resultCode == SecondActivity.BACK_MA_CODE){ textView.setText(data.getStringExtra("who")); } } } }

activity_second.xml:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/text_view_sec" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center"/> <Button android:id="@+id/button_back" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="到数据返回MainActivity" android:textAllCaps="false"/> </LinearLayout>

SecondActivity.java:

package com.android.wrf_mac.activity_deliver; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; public class SecondActivity extends AppCompatActivity { public static final int BACK_MA_CODE = 100; TextView textView; Button back; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); textView = (TextView) findViewById(R.id.text_view_sec); back = (Button) findViewById(R.id.button_back); receiveFormMA(); back.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(); intent.putExtra("who", "I`m SecondActivity"); setResult(BACK_MA_CODE, intent); finish(); } }); } private void receiveFormMA(){ //取到Intent,再取Bundle,再取存入的值 Intent intent = getIntent(); // //bundle = intent.getExtras(); Log.d("SecondActivity", intent.getIntExtra("id", 0) + ""); switch (intent.getIntExtra("id",0)){ case MainActivity.D_BUNDLE: Bundle bundle = intent.getBundleExtra("text"); String name = bundle.getString("name"); int age = bundle.getInt("age"); String des = bundle.getString("des","No describe");//若没有值,给定一个默认值 textView.setText("Name is " + name + ",age is " + age + ",describe is " + des); break; case MainActivity.D_PARCELABLE: Book book = intent.getParcelableExtra("book"); textView.setText("书名:" + book.getBookName() + ", 作者:" + book.getAuthor() + " ,价格: " + book.getPrice()); break; case MainActivity.D_SERIALIZABLE: Person person = (Person) intent.getSerializableExtra("person"); textView.setText("Name is " + person.getName() + ",age is " + person.getAge() + ",address is " + person.getAddress()); break; case MainActivity.D_RESULT: textView.setText(intent.getStringExtra("who")); break; default: textView.setText("没有接收到数据"); } } }

Book.java(使用Parcelable接口传递的类):

package com.android.wrf_mac.activity_deliver; import android.os.Parcel; import android.os.Parcelable; /** * Created by wrf_mac on 2017/7/7. */ public class Book implements Parcelable { private String bookName; private String author; private int price; public void setBookName(String bookName) { this.bookName = bookName; } public void setAuthor(String author) { this.author = author; } public void setPrice(int price) { this.price = price; } public String getBookName() { return bookName; } public String getAuthor() { return author; } public int getPrice() { return price; } // 1.必须实现Parcelable.Creator接口,否则在获取Person数据的时候,会报错,如下: // android.os.BadParcelableException: // Parcelable protocol requires a Parcelable.Creator object called CREATOR on class com.um.demo.Person // 2.这个接口实现了从Parcel容器读取Book数据,并返回Book对象给逻辑层使用 // 3.实现Parcelable.Creator接口对象名必须为CREATOR,不如同样会报错上面所提到的错; // 4.在读取Parcel容器里的数据时,必须按成员变量声明的顺序读取数据,不然会出现获取数据出错 // 5.反序列化对象 public static final Creator<Book> CREATOR = new Creator<Book>() { /** * TODO:安装成员变量的声明顺序读取数据,然后存入Book对象,返回Book对象给逻辑层用 * @param in * @return */ @Override public Book createFromParcel(Parcel in) { Book book = new Book(); book.setBookName(in.readString()); book.setAuthor(in.readString()); book.setPrice(in.readInt()); return book; } //供外部类反序列化本类数组使用 @Override public Book[] newArray(int size) { return new Book[size]; } }; //内容接口描述,默认返回0即刻 @Override public int describeContents() { return 0; } /** * TODO:按照声明顺序打包数据到Parcel对象中,既将数据打包到Parcel容器中 * TODO:使用write***方法打包数据 * @param parcel * @param i */ @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeString(bookName); parcel.writeString(author); parcel.writeInt(price); } }

Person.java(使用Serializable接口传递的类):

package com.android.wrf_mac.activity_deliver; import java.io.Serializable; /** * Created by wrf_mac on 2017/7/8. */ public class Person implements Serializable { static final long serialVersionUID = 3453521L; private String name; private int age; private String address; public String getName() { return name; } public int getAge() { return age; } public String getAddress() { return address; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void setAddress(String address) { this.address = address; } }

本篇博客参考了多名前辈的总结,站在巨人的肩膀上,再次感谢前人。

如有不足和错误,欢迎指出

转载请注明原文地址: https://www.6miu.com/read-49022.html

最新回复(0)