Android---Intent传递字段为Bundle类型的实体

在页面跳转的时候,我们经常使用Intent来传递数据,比如我们要传递一个BundleBean,我们使BundleBean实现Serializable或者Parcelable接口,通过intent.putExtra("data", bean)即可在页面间传递数据。但是,当BundleBean中有一个Bundle类型的字段时,这种方法就不能正常发挥作用了。
代码如下:

public class BundleBean implements Parcelable {

    public int age;
    public Bundle bundle;

    public BundleBean(int age, Bundle bundle) {
        this.age = age;
        this.bundle = bundle;

    }

    protected BundleBean(Parcel in) {
        age = in.readInt();
        bundle = in.readBundle();
    }

    public static final Creator<BundleBean> CREATOR = new Creator<BundleBean>() {
        @Override
        public BundleBean createFromParcel(Parcel in) {
            return new BundleBean(in);
        }

        @Override
        public BundleBean[] newArray(int size) {
            return new BundleBean[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(age);
        dest.writeBundle(bundle);
    }
}
public class SubBean implements Parcelable {
    public int a = 1;

    public SubBean(int a) {
        this.a = a;
    }

    protected SubBean(Parcel in) {
        a = in.readInt();
    }

    public static final Creator<SubBean> CREATOR = new Creator<SubBean>() {
        @Override
        public SubBean createFromParcel(Parcel in) {
            return new SubBean(in);
        }

        @Override
        public SubBean[] newArray(int size) {
            return new SubBean[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(a);
    }
}

在第一个界面传递:

Bundle bundle = new Bundle()
bundle.putParcelable("sub", new SubBean(1))
BundleBean bean = BundleBean(10, bundle)
intent.putExtra("data", bean)
intent.setClass(this, BundleActivity.class)

在第二个界面接收:

Intent intent = getIntent();
BundleBean data = intent.getParcelableExtra("data");
SubBean sub = data.bundle.getParcelable("sub");
if(sub != null) {
   Log.i("tag", sub.a + "");
}

按理说,我们可以在第二个页面接收到数据了?这样想你就大错特错了,你会发现应用崩了,看一下控制台:

android.os.BadParcelableException:ClassNotFoundException when unmarshalling:jzd.myapplication.bundle.bean.SubBean

这是什么原因呢?自习看一下BundleBean类,这里我用Android Studio自动生成了Parcelable中的方法,IDE在

bundle = in.readBundle();

这行有一个提示Using the default class loader will not work if you are restoring your own classes. Consider using for example readBundle(getClass().getClassLoader()) instead,意思是说使用默认的ClassLoader不能“复原”BundleBean中bundle字段中存储的数据,解决的关键点当然是ClassLoader类了。
既然我们bundle中存储了个SubBean,我们自然而然的想到,使用SubBean.class.getClassLoader()来复原里边的数据,我们改造一下BundleBean:将bundle = in.readBundle()改为bundle = in.readBundle(SubBean.class.getClassLoader());然后运行一下,发现数据传递成功了。

到此为止,我们成功使用Intent传递了Bundle类型的数据。

我们再深入一下:为什么我们要使用Bundle类型的字段呢,因为我这个BundleBean中可能会存放不同类型的数据,那我们使用in.readBundle(SubBean.class.getClassLoader())岂不是写死了?如果我使用bundle存放了个User类,岂不是还是传递失败了?那我们怎么解决呢?
我们需要在writeToParcel方法中保存ClassLoader,后面赋值的时候才能使用该ClassLoader:

public class BundleBean implements Parcelable {

    public int age;
    public Bundle bundle;

    public BundleBean(int age, Bundle bundle) {
        this.age = age;
        this.bundle = bundle;

    }

    protected BundleBean(Parcel in) {
        age = in.readInt();
        String name = in.readString();
        if(name != null)
        {
            try {
                bundle = in.readBundle(Class.forName(name).getClassLoader());
            } catch(ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

    }

    public static final Creator<BundleBean> CREATOR = new Creator<BundleBean>() {
        @Override
        public BundleBean createFromParcel(Parcel in) {
            return new BundleBean(in);
        }

        @Override
        public BundleBean[] newArray(int size) {
            return new BundleBean[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(age);

        if(bundle != null) {
            Parcelable sub = bundle.getParcelable("sub");
            if(sub != null) {
                dest.writeString(sub.getClass()
                        .getName());
                dest.writeBundle(bundle);
            }
        }
        //dest.writeBundle(bundle);
    }
}

来测试一下:

Bundle bundle = new Bundle();
bundle.putParcelable("sub", new SubBean(1));
bundle.putInt("sub1", 2);
bundle.putParcelable("sub2", new SubBean(3));
bundle.putParcelable("other", new Other("other"));
val bean = BundleBean(10, bundle);
intent.putExtra("data", bean);
intent.setClass(this, BundleActivity::class.java);
Intent intent = getIntent();
BundleBean data = intent.getParcelableExtra("data");
SubBean sub = data.bundle.getParcelable("sub");
if(sub != null) {
  Log.i("tag", sub.a + "");
}
int sub1 = data.bundle.getInt("sub1");
Log.i("tag", sub1 + "");

SubBean sub2 = data.bundle.getParcelable("sub2");
if(sub2 != null) {
  Log.i("tag", sub2.a + "");
}

Other other = data.bundle.getParcelable("other");
if(other != null) {
  Log.i("tag", other.name);
}

输出:

1
2
3
other

至此,我们的BundleBean中就可以存放任意类型的数据了。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值