Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android:Passing a hash map between Activities

I have a map between string and a class object. I populate this map in Activity1 and i would like to pass it to activity2.

public class NEW extends Activity {

    public class data {
            String name;
            float value;
                 ....   etc  }

 ......   
    static Map<String, data> data_map = new HashMap<String, data>();
   .....  }
like image 725
m4n07 Avatar asked Apr 06 '11 13:04

m4n07


3 Answers

The best way to do this is if you can express your data in the primitives supported by Bundle, so it can be placed in the Intent you are sending through the Intent.putExtra() methods. (EXCEPT for the use of Serializable, which is extremely slow and inefficient.)

However you can't do this because (a) you are using a Map and (b) your map contains a custom data type.

The formally correct solution to this exact problem is to write a custom Parcellable class that takes care of marshalling/unmarshalling your data structure. I'll sketch out the code here, though it may not be exactly correct:

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);
        }
    }
}

Note that when you have a custom data structure like your "data" class, it can be cleaner to also make that Parcellable, so it knows how to read/write its contents in a Parcel, and the code here would just call .writeToParcel(...) and a .readFromParcel(...) method on it instead of knowing the details of its contents. That way when you add new fields to "data" you don't forget to also update this other marshalling code to know about them.

like image 134
hackbod Avatar answered Sep 30 '22 21:09

hackbod


I am assuming you own both Activities (call them A and B). In which case just put the map in a public static variable and access it from B via A.data_map.

[update]

For all of the downvotes take a peek at the Android Application Framework FAQ section "How do I pass data between Activities/Services within a single application?". The solution I recommend is exactly the same as...

A public static field/method

An alternate way to make data accessible across Activities/Services is to use public static fields and/or methods. You can access these static fields from any other class in your application. To share an object, the activity which creates your object sets a static field to point to this object and any other activity that wants to use this object just accesses this static field.

Yes, there are caveats to this solution but with the limited info presented by the OP we can not assume this method will not work.

like image 24
Andrew White Avatar answered Sep 30 '22 22:09

Andrew White


I would suggest using Intents, which work for both static and arbitary objects (as long as they implement Serializable). Create a custom Intent for your application and then pass on your HashMap (not a Map, which doesn't implement Serializable!) as extra data:

Intent act2 = new Intent(Activity2.SHOW_ME);
act2.putExtra("data", data_map);

Then in Activity2, you can call getIntent() and check via Intent.getAction().equals(Activity2.SHOW_ME) whether you were the one calling your Activity. If so, you can access your extra data by

Intent caller = getIntent();
if (caller.getAction().equals(Activity2.SHOW_ME)) {
   Map<String, NEW.data> data_map = (Map<String, NEW.data>)caller.getExtras().get("data");
}

Hope I typed everything correctly ;) This assumes, that your Intent action-string is stored as static final string SHOW_ME = "yourpackage.yourname"; in Activity2.

If you need further clarification, add a comment.

like image 36
Michael Rose Avatar answered Sep 30 '22 23:09

Michael Rose