Android:在活动之间传递哈希映射
Posted
技术标签:
【中文标题】Android:在活动之间传递哈希映射【英文标题】:Android:Passing a hash map between Activities 【发布时间】:2011-07-30 19:55:05 【问题描述】:我有一个字符串和一个类对象之间的映射。我在 Activity1 中填充此地图,我想将其传递给 activity2。
public class NEW extends Activity
public class data
String name;
float value;
.... etc
......
static Map<String, data> data_map = new HashMap<String, data>();
.....
【问题讨论】:
【参考方案1】:最好的方法是如果你可以用 Bundle 支持的原语表达你的数据,那么它可以放在你通过 Intent.putExtra() 方法发送的 Intent 中。 (除了使用Serializable,它非常慢而且效率低。)
但是您不能这样做,因为 (a) 您正在使用地图,并且 (b) 您的地图包含自定义数据类型。
对于这个确切问题的正式正确解决方案是编写一个自定义 Parcellable 类来处理数据结构的编组/解组。我将在这里勾勒出代码,尽管它可能并不完全正确:
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable.Creator;
public class MyData implements Parcelable
HashMap<String, data> data_map = new HashMap<String, data>();
public MyData()
public int describeContents()
return 0;
public void writeToParcel(Parcel dest, int parcelableFlags)
final int N = data_map.size();
dest.writeInt(N);
if (N > 0)
for (Map.Entry<String, data> entry : data_map.entrySet())
dest.writeString(entry.getKey());
data dat = entry.getValue();
dest.writeString(dat.name);
dest.writeFloat(dat.value);
// etc...
public static final Creator<MyData> CREATOR = new Creator<MyData>()
public MyData createFromParcel(Parcel source)
return new MyData(source);
public MyData[] newArray(int size)
return new MyData[size];
;
private MyData(Parcel source)
final int N = source.readInt();
for (int i=0; i<N; i++)
String key = source.readString();
data dat = new data();
dat.name = source.readString();
dat.value = source.readFloat();
// etc...
data_map.put(key, dat);
请注意,当您拥有像“数据”类这样的自定义数据结构时,将其设为 Parcellable 会更简洁,因此它知道如何在 Parcel 中读取/写入其内容,此处的代码只需调用.writeToParcel(...) 和 .readFromParcel(...) 方法,而不是知道其内容的详细信息。这样,当您向“数据”添加新字段时,您不会忘记更新其他编组代码以了解它们。
【讨论】:
@hckbod:“可序列化,非常慢且效率低”你有这个来源吗?我从未见过任何性能问题。 我过去测量过。它很慢。特别是与 Parcelable 相比。相信我。 @hackbod:如果没有某种来源、文档或证据,我不会轻易相信某人的话。由于序列化器可以表示任意对象并且大多数移动数据都是“小”的,我很难推荐它。 @Andrew:是的,关于框确实可能是虚构的。但是有人应该告诉 Dianne Hackborn,她有一个冒名顶替者,出于某种原因,她在 *** 上撰写了大量有关 Android 的深入帖子。 :) 一些基准测试会很好(@Andrew,也许你会为我们承担这项任务?)不要不尊重 Dianne - 我一直很想看到指标。直觉会说序列化/反序列化会对性能产生明显的影响。【参考方案2】:我假设您同时拥有这两个活动(称它们为 A 和 B)。在这种情况下,只需将地图放在一个公共静态变量中,然后通过 A.data_map 从 B 访问它。
[更新]
对于所有反对意见,请查看Android Application Framework FAQ 部分“如何在单个应用程序中的活动/服务之间传递数据?”。我推荐的解决方案与...完全一样。
公共静态字段/方法
另一种制作数据的方法 跨活动/服务访问 是使用公共静态字段和/或 方法。您可以访问这些静态 来自您的任何其他班级的字段 应用。要共享一个对象, 创建您的对象的活动 设置一个静态字段指向这个 对象和任何其他活动 想要使用这个对象只是访问 这个静态字段。
是的,此解决方案有一些注意事项,但由于 OP 提供的信息有限,我们不能假设此方法不起作用。
【讨论】:
不,那是坏的。例如,如果用户离开您的应用程序,它在后台被杀死,然后他们返回,那么当 Activity B 被实例化时,它现在会发现 data_map 为空。 @hackbod:完全没有损坏; B 应该有适当的逻辑来在 onPause 期间保持状态。 这个坏了。严重地。保存该状态需要您执行与将状态传播到新 Activity 完全相同的操作。 迟早你会遇到问题。您需要做的就是回家,终止您的进程,然后返回您的应用程序。您的***活动已重新创建,但您的全局现在重置为空。 @Andrew White 这正是 hackbod 所说的。它会损坏,并且 arraylist 中的数据被清除。它为 arraylist 提供大小为 0。【参考方案3】:我建议使用 Intent,它适用于静态对象和任意对象(只要它们实现 Serializable)。为您的应用程序创建一个自定义Intent,然后将您的 HashMap(不是 Map,它不实现 Serializable!)作为额外数据传递:
Intent act2 = new Intent(Activity2.SHOW_ME);
act2.putExtra("data", data_map);
然后在 Activity2 中,您可以调用 getIntent()
并通过 Intent.getAction().equals(Activity2.SHOW_ME)
检查您是否是调用您的 Activity 的人。如果是这样,您可以通过
Intent caller = getIntent();
if (caller.getAction().equals(Activity2.SHOW_ME))
Map<String, NEW.data> data_map = (Map<String, NEW.data>)caller.getExtras().get("data");
希望我输入的所有内容都正确 ;) 这假设您的 Intent 操作字符串在 Activity2 中存储为 static final string SHOW_ME = "yourpackage.yourname";
。
如果您需要进一步说明,请添加评论。
【讨论】:
我尝试了类似的东西,Intent intent = new Intent("com.android.MYPACKAGE.MYCLASS2"); intent.putExtra("data",data_map);但收到错误消息为“putExtra 方法不适用于参数” 是的,我有。我在没有传递数据的情况下进行了检查,我能够导航到第二个活动。(如第二页)但如果我尝试 intent.putExtra("data",data_map); 则会出现编译错误;由于 putExtra 不带地图。 对不起,是的,这是因为 Map 没有实现 Serializable。您必须将data_map
类型更改为 HashMap<String, data>
。
我强烈建议不要使用Serializable,它非常慢。
好吧,我没有这方面的经验,但是如果他想使用HashMap,它默认实现它。下面的答案 2 将是另一种选择。【参考方案4】:
您可以按照本文档中的说明将数据封装在绑定服务中:
http://developer.android.com/guide/topics/fundamentals/bound-services.html
不要忘记将您的服务器添加到清单文件中。
此解决方案的优势在于将您的数据与您的 UI 分离,这最终会带来更易于维护的设计。
如果需要,您可以将消息包装器添加到服务的 API 以允许从其他进程/应用程序调用它
【讨论】:
【参考方案5】:创建一个新的 java 文件,该文件对整个应用程序都是全局的。
第一步:
public class GlobalClass extends android.app.Application
public static Map<String, NEW.data> data_map = new Map<String, NEW.data>();
第二步:
完成后,在 AndroidManifest.xml 中注册这个“GlobalClass”
<application
android:name=".GlobalClass"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
</application>
第三步:
现在您可以在应用程序的任何位置使用此地图。
@Override
protected void onCreate(Bundle icicle)
GlobalClass global = (GlobalClass)getApplication();
Map<String, NEW.data> my_map_data = global.data_map;
这些步骤可能对你有帮助......
【讨论】:
在 Application 类中存储数据的一大禁忌。当应用程序进入后台时,如果系统杀死您的应用程序,应用程序类将创建一个新实例,而不是原始实例,那么数据将丢失。 (您可以尝试在开发者选项中限制后台进程)以上是关于Android:在活动之间传递哈希映射的主要内容,如果未能解决你的问题,请参考以下文章