Android:在活动之间传递哈希映射

m4n*_*n07 18 android map android-intent android-activity

我在字符串和类对象之间有一个映射.我在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>();
   .....  }
Run Code Online (Sandbox Code Playgroud)

hac*_*bod 53

执行此操作的最佳方法是,如果您可以在Bundle支持的基元中表达您的数据,那么它可以放在您通过Intent.putExtra()方法发送的Intent中.(除了使用Serializable,这是非常缓慢和低效的.)

但是你不能这样做是因为(a)你正在使用Map和(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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,当您拥有类似"数据"类的自定义数据结构时,也可以更简洁地制作Parcellable,因此它知道如何在Parcel中读取/写入其内容,此处的代码只需调用.writeToParcel( ...)和.readFromParcel(...)方法,而不是知道其内容的细节.这样,当您向"数据"添加新字段时,您不会忘记更新此其他编组代码以了解它们.

  • 我过去曾测量过它.这很慢.特别是与Parcelable相比.相信我. (6认同)
  • @hackbod:如果没有某种来源,文件或证据,我就不会只是接受别人的话.由于串行器可以表示任意对象,并且大多数移动数据"很小",因此我很难推荐它. (2认同)
  • @Andrew:是的,关于盒子确实可以制作.但是有人应该告诉Dianne Hackborn她有一个冒名顶替者,由于某种原因,他在StackOverflow上撰写了大量关于Android的深入帖子.:) (2认同)
  • 一些基准会很好(@Andrew,也许你会为我们承担这个任务?)不要对Dianne不尊重 - 我一直很想看到指标.直觉会说序列化/反序列化会产生明显的性能影响. (2认同)

And*_*ite 22

我假设你拥有两个活动(称为A和B).在这种情况下,只需将地图放在公共静态变量中,然后通过A.data_map从B访问它.

[更新]

对于所有的downvotes,请查看Android应用程序框架常见问题解答部分"如何在单个应用程序中的活动/服务之间传递数据?".我推荐的解决方案与......完全相同

公共静态字段/方法

使活动/服务可访问数据的另一种方法是使用公共静态字段和/或方法.您可以从应用程序中的任何其他类访问这些静态字段.要共享对象,创建对象的活动会将静态字段设置为指向此对象,而要使用此对象的任何其他活动只会访问此静态字段.

是的,这个解决方案有一些警告,但由于OP提供的信息有限,我们不能假设这种方法不起作用.

  • 不,这打破了.例如,如果用户离开您的应用程序,它将在后台被杀死并返回,然后当实例化活动B时,它现在将发现data_map为null. (21认同)
  • 这已破了.认真.保存该状态需要您执行完全相同的操作,因为您需要将状态传播到新活动. (9认同)
  • 迟早你会遇到问题.您需要做的就是回家,杀死您的流程,然后返回到您的应用.您的顶级活动已重新创建,但您的全局现已重置为空. (4认同)
  • @hackbod:完全不打破; B应该具有适当的逻辑以在onPause期间保持状态. (2认同)

Mic*_*ose 5

我建议使用Intents,它既适用于静态对象又适用于任意对象(只要它们实现Serializable).为您的应用程序创建一个自定义Intent,然后将您的HashMap(不是Map,它不实现Serializable!)作为额外数据传递:

Intent act2 = new Intent(Activity2.SHOW_ME);
act2.putExtra("data", data_map);
Run Code Online (Sandbox Code Playgroud)

然后在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");
}
Run Code Online (Sandbox Code Playgroud)

希望我正确键入所有内容;)这假设您的Intent操作字符串存储static final string SHOW_ME = "yourpackage.yourname";在Activity2中.

如果您需要进一步说明,请添加评论.