活动之间共享数据的最佳方式是什么?
我有一个活动,这是整个应用程序使用的主要活动,它有一些variables。 我还有其他两项活动,我希望能够使用第一项活动的数据。 现在我知道我可以做这样的事情:
GlobalState gs = (GlobalState) getApplication(); String s = gs.getTestMe();
不过,我想分享很多变数,有些可能相当大,所以我不想像上面那样创build它们的副本。
有没有办法直接获取和更改variables,而不使用get和set方法? 我记得在Google dev的网站上看过一篇文章,说这不是build议在Android上的performance。
这里有一个最常见的方法来达到这个汇编:
- 在意图内发送数据
- 静态字段
-
WeakReferences
HashMap - 坚持对象(sqlite,共享首选项,文件等)
TL; DR :共享数据有两种方式:将数据传递给intent的extras或将其保存在其他地方。 如果数据是基元,string或用户定义的对象:将其作为意图附加的一部分发送(用户定义的对象必须实现Parcelable
)。 如果传递复杂对象,则将某个实例保存在其他地方的单例中,并从已启动的活动中访问它们。
一些如何以及为什么要实施每种方法的例子:
发送意图内的数据
Intent intent = new Intent(FirstActivity.this, SecondActivity.class); intent.putExtra("some_key", value); intent.putExtra("some_other_key", "a value"); startActivity(intent);
关于第二项活动:
Bundle bundle = getIntent().getExtras(); int value = bundle.getInt("some_key"); String value2 = bundle.getString("some_other_key");
如果传递原始数据或string,请使用此方法。 你也可以传递实现Serializable
对象。
虽然有诱惑力,但在使用Serializable
之前,你应该三思:它容易出错,速度很慢。 所以一般来说:如果可能的话, 远离Serializable
。 如果你想传递复杂的用户定义的对象, 请看一下Parcelable
接口 。 实现起来比较困难,但是与Serializable
相比,它的速度有了相当大的提高。
共享数据而不需要保存到磁盘
考虑到在大多数情况下,两个活动在相同的过程中运行,可以在活动之间共享数据。
注意:有时,当用户离开您的活动(不放弃)时,Android可能决定终止您的应用程序。 在这种情况下,我遇到了一些情况,在这些情况下,android尝试使用在应用程序被终止前提供的意图来启动上一个活动。 在这种情况下,存储在单例(您的或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;} }
从推出的活动:
String data = DataHolder.getInstance().getData();
使用应用程序单例
应用程序单例是在应用程序启动时创build的android.app.Application
一个实例。 您可以通过扩展Application
来提供自定义的一个:
import android.app.Application; public class MyApplication extends Application { private String data; public String getData() {return data;} public void setData(String data) {this.data = data;} }
在开展活动之前:
MyApplication app = (MyApplication) getApplicationContext(); app.setData(someData);
然后,从已启动的活动:
MyApplication app = (MyApplication) getApplicationContext(); String data = app.getData();
静态字段
这个想法基本上与单例相同,但在这种情况下,您提供了对数据的静态访问:
public class DataHolder { private static String data; public static String getData() {return data;} public static String setData(String data) {DataHolder.data = data;} }
从推出的活动:
String data = DataHolder.getData();
WeakReferences
HashMap
同样的想法,但允许垃圾收集器删除未引用的对象(例如,当用户退出活动):
public class DataHolder { Map<String, WeakReference<Object>> data = new HashMap<String, WeakReference<Object>>(); void save(String id, Object object) { data.put(id, new WeakReference<Object>(object)); } Object retrieve(String id) { WeakReference<Object> objectWeakReference = data.get(id); return objectWeakReference.get(); } }
在开展活动之前:
DataHolder.getInstance().save(someId, someObject);
从推出的活动:
DataHolder.getInstance().retrieve(someId);
您可能需要也可能不需要使用intent的extras来传递对象id。 这一切都取决于你的具体问题。
坚持对象到磁盘
这个想法是在启动其他活动之前将数据保存在磁盘中。
优点:你可以从其他地方启动活动,如果数据已经存在,它应该可以正常工作。
缺点:这很麻烦,需要更多时间来实施。 需要更多的代码,从而更多的机会引入错误。 这也会慢得多。
坚持对象的一些方法包括:
- 将它们保存到共享首选项
- 将它们保存到一个sqlite数据库
- 保存到一个文件(我会避免这个)
你可以使用什么:
- 在活动之间传递数据(如Cristian说)
- 使用一个有很多静态variables的类(所以你可以在没有类的实例的情况下调用它们,而不使用getter / setter)
- 使用数据库
- 共享首选项
你select什么取决于你的需求。 当你有“很多”的时候,你可能会用不止一种方式,
“但是我想分享很多变数,有些可能相当大,所以我不想像上面那样创build它们的副本。
这不是一个副本(特别是与string ,但即使对象传递的价值引用,而不是对象本身,而且这样的getter是很好用 – 可以比其他方式使用更好,因为它们是常见的,完全了解)。 较旧的“表演神话”,例如不使用吸气器和吸气器,仍然有一定的价值,但在文档中也进行了更新 。
但是如果你不想这么做的话,你也可以在GlobalState中公开或者保护这些variables,并直接访问它们。 而且,您可以创build一个静态的单例,如Application对象JavaDoc所示 :
通常不需要子类Application。 在大多数情况下,静态单例可以以更模块化的方式提供相同的function。 如果你的单例需要一个全局上下文(例如注册广播接收者),那么检索它的函数可以被赋予一个Context,它在第一次构造单例时在内部使用Context.getApplicationContext()。
使用Intent数据,这里的其他答案是另一种传递数据的方式,但通常用于较小的数据和简单的types。 您可以传递更大/更复杂的数据,但是比使用静态单元更复杂。 尽pipeAndroid应用程序组件之间共享更大/更复杂的非持久性数据,但Application对象仍然是我个人最喜欢的(因为它在Android应用程序中有一个定义良好的生命周期)。
另外,正如其他人已经指出,如果数据变得非常复杂,需要持久化,那么你也可以使用SQLite或文件系统。
做什么谷歌命令你做! 这里: http : //developer.android.com/resources/faq/framework.html#3
- 原始数据types
- 非持久对象
- 单身class – 我的最爱:D
- 公共静态字段/方法
- 弱引用的对象的HashMap
- 持久对象(应用程序首选项,文件,contentProviders,SQLite数据库)
您可以扩展应用程序类和标签上的任何对象,然后在应用程序的任何地方
使用上面介绍的弱引用方法的hashmap和http://developer.android.com/guide/faq/framework.html似乎对我来说是有问题的。; 整个条目如何被回收,而不仅仅是地图值? 你分配的范围是什么? 由于框架控制着Activity的生命周期,当拥有者参与其中一个活动时,如果拥有者在其客户之前遭到破坏,就会面临运行时错误。 如果应用程序拥有它,则某些活动必须明确地删除条目,以避免哈希映射保留有有效密钥的条目和可能被垃圾收集的弱引用。 而且,当一个密钥返回的值为空时,客户端应该做什么?
在我看来,应用程序拥有的一个WeakHashMap或者在一个单例中是一个更好的select。 地图中的一个值是通过一个关键对象来访问的,当没有强关键字的存在时(即所有的活动都是通过关键字和地图来完成的),GC可以回收地图条目。
那么我有几个想法,但我不知道你是否在寻找什么。
您可以使用包含所有数据的服务,然后将您的活动绑定到服务以进行数据检索。
或者将你的数据打包成一个可序列化或可分区的,并将它们附加到一个bundle中,并在这些活动之间传递这个bundle。
这个可能根本不是你想要的,但是你也可以尝试使用SharedPreferences或者一般的偏好。
无论哪种方式,让我知道你的决定。
假设您使用Intent从活动一中调用活动二。
你可以用intent.putExtra()传递数据,
以此为参考。 用Intent.putExtra发送数组
希望这就是你想要的。
如果您打算从当前活动中调用其他活动,则应该使用Intents 。 您的重点可能不在于坚持数据,而是根据需要分享数据。
但是,如果您确实需要坚持这些值,那么您可以将它们存储在本地存储上的某种结构化文本文件或数据库中。 属性文件,XML文件或JSON文件可以存储您的数据,并在创build活动期间轻松parsing。 不要忘记,你在所有Android设备上都有SQLite,所以你可以将它们存储在数据库表中。 您也可以使用Map来存储键值对并将映射序列化到本地存储,但是这对于简单的数据结构来说可能太麻烦了。
所有上述的答案是伟大的…我只是增加一个没有人提到通过活动持续数据,这是使用内置的Android SQLite数据库来坚持相关的数据…其实你可以把你的databaseHelper在应用程序状态,并根据需要在整个激活过程中调用它。或者只是build立一个辅助类,并在需要时进行数据库调用…只需添加另一个层供您考虑…但所有其他答案就足够了以及..真的只是喜好
活动示例之间共享数据login后传递电子邮件的示例
“email”是可以用来引用被请求的活动的值的名字
1login页面上的代码
Intent openLoginActivity = new Intent(getBaseContext(), Home.class); openLoginActivity.putExtra("email", getEmail);
2个代码在主页上
Bundle extras = getIntent().getExtras(); accountEmail = extras.getString("email");
如果你想使用数据对象,这两个实现非常重要:
可序列化与Parcelable
- 可串行化是一个标记接口,这意味着用户不能按照他们的要求编组数据。 所以当对象实现Serializable时,Java会自动序列化它。
- Parcelable是Android自己的序列化协议。 在Parcelable中,开发人员编写用于编组和解组的自定义代码。 所以与序列化相比,它创build了更less的垃圾对象
- 由于其自定义实现,与可序列化相比,Parcelable的性能非常高。强烈build议在android中序列化对象时使用Parcelable注入。
public class User implements Parcelable
在这里检查更多
**There are various way to share data between activities** 1: **passing data between activities using Intent** Intent intent=new Intent(this, desirableActivity.class); intent.putExtra("KEY", "Value"); startActivity(intent) 2: Using static keyword , define variable as public static and use any where in project public static int sInitialValue=0; use anywhere in project using classname.variableName; 3: Using Database but its bit lengthy process, you have to use query for inserting data and iterate data using cursor when need. but there are no chance of losing data without cleaning cache. 4: Using shared Preferences much easier than database. but there is some limitation you can not save ArrayList ,List and custome objects. 5: Create getter setter in Aplication class and access any where in project. public String getData() { return data; } public void setData(String data) { this.data = data; } private String data; here set and get from activities ((YourApplicationClass)getApplicationContext()).setData("abc"); String data=((YourApplicationClass)getApplicationContext()).getData();