Activity间数据传递方法汇总

在Activity间传递的数据一般比较简单,但是有时候实际开发中也会传一些比较复杂的数据,本节一起来学习更多Activity间数据的传递。

一、常用数据类型

在前面几节我们只学习了一些常用类型的数据传递,主要是以下这些重载方法:

  • putExtra(String name, boolean value)
  • putExtra(String name, byte value)
  • putExtra(String name, char value)
  • putExtra(String name, short value)
  • putExtra(String name, int value)
  • putExtra(String name, long value)
  • putExtra(String name, float value)
  • putExtra(String name, double value)
  • putExtra(String name, String value)
  • putExtra(String name, CharSequence value)
  • putExtras(Intent src)
  • putExtras(Bundle extras)
  • putExtra(String name, Bundle value)
  • getBooleanExtra(String name, boolean defaultValue)
  • getByteExtra(String name, byte defaultValue)
  • getCharExtra(String name, char defaultValue)
  • getShortExtra(String name, short defaultValue)
  • getIntExtra(String name, int defaultValue)
  • getLongExtra(String name, long defaultValue)
  • getFloatExtra(String name, float defaultValue)
  • getDoubleExtra(String name, double defaultValue)
  • getStringExtra(String name)
  • getCharSequenceExtra(String name)
  • getExtras()
  • getBundleExtra(String name)

可以发现主要包括boolean、byte、char、short、int、long、float、double、String、CharSequence几个,当然也可以先将数据打包为Bundle或Intent对象再传递。

二、数组、列表类型数据

然而在实际开发中经常会遇见以上常用类型的数组或列表的组合型数据,其实也非常简单。

01数组

认真的同学可能已经发现了,每一个基本数据类型都有对应数组数据的重载方法,分别如下:

  • putExtra(String name, boolean[] value)
  • putExtra(String name, byte[] value)
  • putExtra(String name, short[] value)
  • putExtra(String name, char[] value)
  • putExtra(String name, int[] value)
  • putExtra(String name, long[] value)
  • putExtra(String name, float[] value)
  • putExtra(String name, double[] value)
  • putExtra(String name, String[] value)
  • putExtra(String name, CharSequence[] value)
  • getBooleanArrayExtra(String name)
  • getByteArrayExtra(String name)
  • getShortArrayExtra(String name)
  • getCharArrayExtra(String name)
  • getIntArrayExtra(String name)
  • getLongArrayExtra(String name)
  • getFloatArrayExtra(String name)
  • getDoubleArrayExtra(String name)
  • getStringArrayExtra(String name)
  • getCharSequenceArrayExtra(String name)

putExtra()方法的参数简单替换为数组类型的即可,然后使用数组的专用方法获取,使用起来也非常简单。

02列表

在传递列表型数据的时候稍微有一些不同了,Intent还提供了以下这几个重载方法:

  • putIntegerArrayListExtra(String name, ArrayList<Integer> value)
  • putStringArrayListExtra(String name, ArrayList<String> value)
  • putCharSequenceArrayListExtra(String name, ArrayList<CharSequence> value)
  • getIntegerArrayListExtra(String name)
  • getStringArrayListExtra(String name)
  • getCharSequenceArrayListExtra(String name)

从以上几个方法可以知道,Intent自带传递Integer、String、CharSequence三种类型的列表数据,如果需要传递到额数据是这几种类型,或能够转换为这几种类型,那么数据的传递也变得很顺利了。

三、对象

前面学习的几个方法使用起来还是比较简单的,但是会发现一个问题,以上学习的方法无法传输对象(如图片)、对象的数组或集合,那就需要用到以下这些方法了。

intent还有以下这些重载方法:

  • putExtra(String name, Serializable value)
  • putExtra(String name, Parcelable value)
  • putExtra(String name, Parcelable[] value)
  • putParcelableArrayListExtra(String name, ArrayList<? extends Parcelable> value)
  • getSerializableExtra(String name)
  • getParcelableExtra(String name)
  • getParcelableArrayExtra(String name)
  • getParcelableArrayListExtra(String name)

可能你已经发现了,这里提到的Serializable类型和Parcelable类型数据到底是什么呢?接下来分别来学习。

01序列化对象Serializable

Serializable接口是启用其序列化功能的接口,实现java.io.Serializable 接口的类是可序列化的,没有实现此接口的类将不能使它们的任一状态被序列化或逆序列化(如果不懂序列化,建议复习巩固Java部分的序列化知识模块)。

Serializable实现序列化的方法也很简单,将需要序列化的类实现Serializable接口,Serializable接口中没有任何方法,只需在类中指定serialVersionUID的值,该值可以任意指定一个值。可以理解为一个标记,即表明这个类可以序列化。

假如需要使用Intent传递一个Person对象,就先要将其序列化,如下示例代码:

public class Person implements Serializable {    private static final long serialVersionUID = 1L; // 序列化 ID    private String name; // 姓名    private int age; // 年龄    public Person() {        this.name = "未知";        this.age = 18;    }    public Person(String name, int age) {        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }}

然后即可调用前面的put和get方法来传递复杂对象数据了。

02序列化对象Parcelable

由于Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC,会影响持续性能。在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。

实现Parcelable接口稍微复杂一些,但效率更高,推荐用这种方法提高性能。实现步骤如下:

  1. 将需要序列化的类实现Parcelable接口。
  2. 重写writeToParcel方法,将对象序列化为一个Parcel对象。
  3. 重写describeContents方法,描述内容接口,默认返回0。实例化静态内部对象CREATOR实现接口Parcelable.Creator。其中public static final一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写。需重写本接口中的两个方法:
    • createFromParcel(Parcel in) 实现从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层。
    • newArray(int size) 创建一个类型为T,长度为size的数组,仅一句话即可(return new T[size]),供外部类反序列化本类数组使用。

接下来将上面的Person类进行改造,代码如下:

public class Person implements Parcelable {    private String name; // 姓名    private int age; // 年    protected Person(Parcel in) {        name = in.readString();        age = in.readInt();    }    public static final Creator<Person> CREATOR = new Creator<Person>() {        // 再通过createFromParcel将Parcel对象映射成原对象        @Override        public Person createFromParcel(Parcel in) {            return new Person(in);        }        @Override        public Person[] newArray(int size) {            return new Person[size];        }    };    @Override    public int describeContents() {        return 0;    }    // 通过writeToParcel将你的对象映射成Parcel对象    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeString(name);        dest.writeInt(age);    }    public Person() {        this.name = "未知";        this.age = 18;    }    public Person(String name, int age) {        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }}

然后即可调用前面的put和get方法来传递复杂对象数据了,当然也可以是对象的数组或列表型数据。

在使用中需要注意的是,Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable。

四、全局Application

如果需要将一个对象在多个Activity之间传递,或者要连续传递好几层,这种情况下如果使用以上方法就需要重复多次,使用起来就特别别扭,这种情况就可以考虑使用全局Application。

Android系统在每个程序运行的时候都会创建一个Application对象,而且只会创建一个,所以Application 是单例(singleton)模式的一个类,而且Application对象的生命周期是整个程序中最长的,他的生命周期等于这个程序的生命周期。如果想存储一些值,使用 Application就需要自定义类实现Application类,然后在AndroidManifest.xml中使用我们自定义的Application 而非系统默认的。

这里简单使用一个示例来学习,这里简化为全局保存一个状态值,可以方便在各Activity中进行传递。首先自定义Application类,代码如下:

public class MyApplication extends Application {    private int state;    public int getState() {        return state;    }    public void setState(int state) {        this.state = state;    }}

然后在AndroidManifest.xml中声明,为application标签添加android:name属性,代码如下:

    <application        android:name=".MyApplication"        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@style/AppTheme">        <activity android:name=".MainActivity" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application>

最后在需要使用定义的全局变量的地方即可调用,核心代码如下:

public class TestActivity extends AppCompatActivity {    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_shop);        ...        MyApplication app = (MyApplication) getApplicationContext();        // 保存数据        app.setState(1);        ...        // 读取数据        int state = app.getState();        ...    }}

这样就非常方便的在各Activity之间进行数据传递了。如果想要在整个应用程序中任何位置都能使用,可以对MyApplication类进行适当的改造,这里不做过多说明。

但是需要注意的是,当由于某些原因(比如系统内存不足),我们的app会被系统强制杀死,此时再次点击进入应用时,系统会直接进入被杀死前的那个界面,制造一种从来没有被杀死的假象。那么问题来了,系统强制停止了应用,进程死了,那么再次启动时Application自然新的,那里边的数据自然木有啦,如果直接使用很可能报空指针或者其他错误。

所以在使用时一定要做好非空判断,如果数据为空可以考虑逻辑上让应用直接返回到最初的Activity。

五、单例模式

上面的Application就是基于单例的,单例模式的特点就是可以保证系统中一个类有且只有一个实例。

这里做一个简单的示例,如定义一个数据持有者类,代码如下:

public class DataHolder {    private String data;    public String getData() {        return data;    }    public void setData(String data) {        this.data = data;    }    private static final DataHolder holder = new DataHolder();    public static DataHolder getInstance() {        return holder;    }}

然后在使用的地方即可直接调用,如下所示:

    // 更新数据    DataHolder.getInstance().setData(data);    // 获取数据    String data = DataHolder.getInstance().getData();

这样使用起来也非常简单。

六、静态变量

这个可以直接在Activity中完成单独一个数据结构,和单例差不多。

这里将上面的单例模式类简单修改,代码如下:

public class DataHolder {    private static String data;    public static String getData() {        return data;    }    public static void setData(String data) {        data = data;    }}

这样就可以在启动Activity之前设置数据,新的Activity中获取数据。

    // 更新数据    DataHolder.setData(data);    // 获取数据    String data = DataHolder.getData();

需要注意的是,如果数据很大很多(如bitmap),处理不当是很容易导致内存泄露或者内存溢出的,可以考虑使用WeakReferences 将数据包装起来。

除了以上介绍的几种方式,还可以使用持久化数据等方法,这里先不做过多介绍,在后续的学习中会陆续接触到。

写在最后

今天就先到这里,如果有问题欢迎留言一起探讨,也欢迎加入Android零基础入门技术讨论微信群,共同成长!

如果该系列分享对你有帮助,就动动手指关注、点赞、留言吧,你的互动就是对我最大的鼓励!

此文章版权为微信公众号分享达人秀(ShareExpert)——鑫鱻所有,若需转载请联系作者授权,特此声明!

本文分享自微信公众号 - 分享达人秀(ShareExpert)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-10-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏黒之染开发日记

js中“||”和“&&”的高级用法

没想到会有人收藏,而且这些不是我自己悟出来的,是网络上找到的一篇文章我读懂后转过来的,原文是http://www.jb51.net/article/21339....

52720
来自专栏Netkiller

Solidity 智能合约开发语言·数据类型

中国广东省深圳市龙华新区民治街道溪山美地 518131 +86 13113668890 <netkiller@msn.com>

780100
来自专栏WindCoder

JSON中关于对双向关联的支持

本文原文:Bidirectional Relationship Support in JSON

22720
来自专栏积累沉淀

【译】Java 8的新特性—终极版

声明:本文翻译自Java 8 Features Tutorial – The ULTIMATE Guide,翻译过程中发现并发编程网已经有同学翻译过了:...

270100
来自专栏一个会写诗的程序员的博客

ES6 极简教程(ES6 Tutorial) 文 / 东海陈光剑ES6 极简教程(ES6 Tutorial)Kotlin 开发者社区

JavaScript是ECMAScript的实现和扩展,由ECMA(一个类似W3C的标准组织)参与进行标准化。ECMAScript定义了:

11130
来自专栏三好码农的三亩自留地

Java反射—写给自己的总结

上面反射是Oracle官方文档的定义,反射能够突破访问权限控制,这还是很优秀的,但是,问题来了,为什么需要反射或者说什么情况下需要用反射?

19920
来自专栏纯洁的微笑

Java 8的新特性—终极版

1. 简介 毫无疑问,Java 8是Java自Java 5(发布于2004年)之后的最重要的版本。这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特...

43660
来自专栏函数式编程语言及工具

Scalaz(53)- scalaz-stream: 程序运算器-application scenario

    从上面多篇的讨论中我们了解到scalaz-stream代表一串连续无穷的数据或者程序。对这个数据流的处理过程就是一个状态机器(state machine...

20790
来自专栏一个会写诗的程序员的博客

第9章 文件IO操作、正则表达式与多线程第9章 文件IO操作、正则表达式与多线程

我们在《第6章 扩展函数与属性》中已经介绍过Kotlin中的类扩展的特性。使用Kotlin的扩展函数功能,我们可以直接为 String 类实现一个 inc() ...

12930
来自专栏程序猿DD

JDK 1.5 - 1.8 各版本的新特性总结

此文章意在借鉴前人经验,留作日后查看。如有侵犯,实属无意。我以后会注意,谢谢博友的提醒。也愿各大博友们能够共同学习和努力。

80060

扫码关注云+社区

领取腾讯云代金券