16

I'm currently writing an app that pulls an array of longs from a server via json, and then passes that list from one activity into another. The basic skeleton looks like this:

public void onResponse(Map result)
{
    ArrayList handles= (ArrayList)result.get("fileHandles");

    Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
    intent.putExtra("handles", handles);
}

So the first problem becomes evident, the only methods for putExtra are putIntegerArrayListExtra, putStringArrayListExtra, putCharSequenceArrayListExtra, and putParcelableArrayListExtra. Thinking Long would probably be parcelable, I was wrong it doesn't work (even if I use ArrayList<Long>). Next I thought I'd just pass a long [], however I see no straight-forward conversion to go from ArrayList<Long> to long [] that intent.putExtra will accept. This was the solution I finally ended up with:

ArrayList handles= (ArrayList)result.get("fileHandles");
long [] handleArray = new long[handles.size()];
for (int i = 0; i < handles.size(); i++)
{
    handleArray[i] = Long.parseLong(handles.get(i).toString());
}

Obviously this seemed a little bit ridiculous to me, but every other conversion I tried seemed to complain for one reason or another. I've thought about re-thinking my serialization to have the problem taken care of before I get to this point, but I find it odd that passing ArrayList<Long> from activity to activity could be so difficult. Is there a more obvious solution I'm missing?

Kevin DiTraglia
  • 25,746
  • 19
  • 92
  • 138
  • FWIW: `Long.parseLong(handles.get(i).toString());` can be written as `(long)(Long)handles.get(i)` (the `(long)` is actually optional in context) when the source is an `ArrayList`. It uses a dowcast and then an explicit (or implicit) un-autobox instead of Long->String->long. – user2864740 Oct 07 '14 at 21:08
  • @user2864740 The problem is `handles.get(i)` is giving me back an Integer if it's under 2 billion or so, which results in an invalid cast if I use that code. – Kevin DiTraglia Oct 13 '14 at 18:39

2 Answers2

21

You can use it as a Serializable extra. ArrayList is Serializable and Long extends Number which also implements Serializable:

// Put as Serializable
i.putExtra("handles", handles);

// Unfortunately you'll get an unsafe cast warning here, but it's safe to use
ArrayList<Long> handles = (ArrayList<Long>) i.getSerializableExtra("handles");    
Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
3

Two options: Use Parcelable or Serializable

in:

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("handles", new FileHandles(handles));

out:

FileHandles handles = intent.getParcelableExtra("handles");

object:

import android.os.Parcel;
import android.os.Parcelable;

import java.util.ArrayList;
import java.util.List;

public class FileHandles implements Parcelable {

    private final List<Long> fileHandles;

    public FileHandles(List<Long> fileHandles) {
        this.fileHandles = fileHandles;
    }

    public FileHandles(Parcel in) {
        int size = in.readInt();
        long[] parcelFileHandles = new long[size];
        in.readLongArray(parcelFileHandles);
        this.fileHandles = toObjects(size, parcelFileHandles);
    }

    private List<Long> toObjects(int size, long[] parcelFileHandles) {
        List<Long> primitiveConv = new ArrayList<Long>();
        for (int i = 0; i < size; i++) {
            primitiveConv.add(parcelFileHandles[i]);
        }
        return primitiveConv;
    }

    public List<Long> asList() { // Prefer you didn't use this method & added domain login here, but stackoverflow can only teach so much..
        return fileHandles;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(fileHandles.size());
        dest.writeLongArray(toPrimitives(fileHandles));
    }

    private static long[] toPrimitives(List<Long> list) {
        return toPrimitives(list.toArray(new Long[list.size()]));
    }

    public static long[] toPrimitives(Long... objects) {
        long[] primitives = new long[objects.length];
        for (int i = 0; i < objects.length; i++)
            primitives[i] = objects[i];

        return primitives;
    }

    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        @Override
        public FileHandles createFromParcel(Parcel in) {
            return new FileHandles(in);
        }

        @Override
        public FileHandles[] newArray(int size) {
            return new FileHandles[size];
        }
    };
}

Serializable (forced to use ArrayList which implements Serializable (List does not)

in:

    Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
    intent.putExtra("handles", new ArrayList<Long>());

out:

    ArrayList handles = (ArrayList) intent.getSerializableExtra("handles");
Blundell
  • 75,855
  • 30
  • 208
  • 233
  • Thanks for the answer. I looked into the parcelable option but it seemed worse than the ugly conversion. The `Serializable` options seems to be the easiest solution to the problem. – Kevin DiTraglia Oct 07 '14 at 21:15
  • `Serializable` with a forced use of `ArrayList` is the easier option. `Parcelable` is Androids version of `Serializable` http://developer.android.com/reference/android/os/Parcelable.html it is optimised for mobile and large data sets. I would always recommend `Serializable` but if you have 1000's of items in your list and pass it around a lot, I would recommend you research `Parcelable` to consider as a performance gain – Blundell Oct 07 '14 at 21:17
  • Thanks, I'll keep it in mind. I think it'll be OK in my use case, it's no more than 5-10 long values. – Kevin DiTraglia Oct 08 '14 at 00:06