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

传递基本数据类型参数

使用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;
    }
}

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

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值