在活动之间共享数据的最佳方式是什么?

问题

我有一个活动,它是整个应用程序中使用的主要活动,它有许多变量。我有两个其他活动,我希望能够使用第一个活动的数据。现在我知道我可以这样做:

GlobalState gs = (GlobalState) getApplication();
String s = gs.getTestMe();

但是我想分享很多变量,有些变量可能相当大,所以我不想像上面那样创建它们的副本。

有没有办法直接获取和更改变量而不使用get和set方法?我记得在Google开发网站上阅读了一篇文章,称不建议在Android上使用此功能。


#1 热门回答(431 赞)

这里汇编了most common ways to achieve this

  • 在意图内发送数据
  • 静态字段
  • WeakReferences的HashMap
  • 持久对象(sqlite,共享首选项,文件等)

TL; DR:有两种共享数据的方式:在intent的附加内容中传递数据或将其保存在其他位置。如果数据是基元,字符串或用户定义的对象:将其作为意图附加项的一部分发送(用户定义的对象必须实现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");

如果要传递基本数据或字符串**,请使用此方法**.你还可以传递实现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();

###使用应用程序单例

应用程序单例是启动应用程序时创建的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的附加内容传递对象ID。这一切都取决于你的具体问题。

#将对象保留到磁盘

想法是在启动其他活动之前将数据保存在磁盘中。

**优点:**你可以从其他地方启动活动,如果数据已经存在,它应该可以正常工作。

**缺点:**it繁琐且需要更多时间来实施。需要更多代码,因此更有可能引入错误。它也会慢得多。

一些持久化对象的方法包括:

  • 将它们保存到共享首选项
  • 将它们保存到sqlite数据库
  • 将它们保存到文件中(我会避免这个)

#2 热门回答(22 赞)

你可以用什么:

  • 在活动之间传递数据(如Cristian所说)
  • 使用具有大量静态变量的类(因此你可以在没有类的实例且不使用getter / setter的情况下调用它们)
  • 使用数据库
  • 共享首选项

你的选择取决于你的需求。当你有"很多"时,你可能会使用多种方式


#3 热门回答(15 赞)

做google命令你做什么!在这里:http://developer.android.com/resources/faq/framework.html#3

  • 原始数据类型
  • 非持久对象
  • 单身课 - 我最喜欢的:D
  • 公共静态字段/方法
  • WeakReferences对象的HashMap
  • 持久对象(应用程序首选项,文件,contentProviders,SQLite DB)