0

I'm using a custom parcelable object called GameSettings to pass a number of settings between Activites within an Android app (developed using MonoDroid). The settings are stored as properties on this GameSettings class, and up until now they've all been simple integers which I've been able to parcel just fine using Parcel.WriteInt() and Parcel.ReadInt().

I've just added a new property to GameSettings called CelebrityNames which is of type List<string>, and I'm trying to pass this in the same way but when ReadStringList() is called the property gets populated with an empty list (despite a non-empty list being written to the parcel prior to this using WriteStringList()). The parcel is being passed from NameEntryActivity to GameRoundActivity.

GameSettings.cs

using System;
using System.Collections.Generic;
using Android.OS;
using Java.Interop;
using Object = Java.Lang.Object;

namespace Celebrities
{
    public class GameSettings : Object, IParcelable
    {
        private static readonly GenericParcelableCreator<GameSettings> _creator 
            = new GenericParcelableCreator<GameSettings>((parcel) => new GameSettings(parcel));

        [ExportField("CREATOR")]
        public static GenericParcelableCreator<GameSettings> InitializeCreator() 
        {
            return _creator;
        }

        public int NumberOfPlayers { get; set; }
        public int NumberOfTeams { get; set; }
        public int CelebritiesPerPlayer { get; set; }
        public int SecondsPerRound { get; set; }

        private List<string> _celebrityNames;
        public List<string> CelebrityNames { 
            get 
            {
                _celebrityNames.Shuffle ();
                return _celebrityNames;
            } 
            set 
            { 
                _celebrityNames = value;
            } 
        }

        public GameSettings (int players, int teams, int celebrities, int secondsPerRound)
        {
            NumberOfPlayers = players;
            NumberOfTeams = teams;
            CelebritiesPerPlayer = celebrities;
            SecondsPerRound = secondsPerRound;
        }

        private GameSettings(Parcel parcel) : this(parcel.ReadInt (), parcel.ReadInt (), parcel.ReadInt (), parcel.ReadInt ())
        {
            if (_celebrityNames == null)
            {
                _celebrityNames = new List<string>();
            }
            parcel.ReadStringList (_celebrityNames);
        }

        public void WriteToParcel(Parcel dest, ParcelableWriteFlags flags) 
        {
            dest.WriteInt (NumberOfPlayers);
            dest.WriteInt (NumberOfTeams);
            dest.WriteInt (CelebritiesPerPlayer);
            dest.WriteInt (SecondsPerRound);
            dest.WriteStringList (_celebrityNames);
        }

        public int DescribeContents() 
        {
            return 0;
        }
    }
}

Note: I'm using the backing variable _celebrityNames for parcelling as I have a custom getter that shuffles the list, which isn't necessary at this point. The problem is the same whether using the property or the variable.

GenericParcelableCreator.cs

using System;
using Android.OS;
using Object = Java.Lang.Object;

namespace Celebrities
{
    public sealed class GenericParcelableCreator<T> : Object, IParcelableCreator
        where T : Object, new()
    {
        private readonly Func<Parcel, T> _createFunc;

        public GenericParcelableCreator(Func<Parcel, T> createFromParcelFunc)
        {
            _createFunc = createFromParcelFunc;
        }

        public Object CreateFromParcel(Parcel source)
        {
            return _createFunc(source);
        }

        public Object[] NewArray(int size)
        {
            return new T[size];
        }
    }
}

I'm including the relevant code from the Activity classes below (these are not the complete files for brevity, please ask if you think it would be helpful to see the rest too).

NameEntryActivity.cs (where I'm passing the parcel from)

public class NameEntryActivity : Activity
{
    ...    

    private GameSettings _gameSettings;
    private List<string> _celebrityNames;

    protected override void OnCreate (Bundle savedInstanceState)
    {
        ...

        _gameSettings = (Intent.Extras.GetParcelable ("GameSettings") as GameSettings);
        _celebrityNames = new List<string> ();

        ...
    }

    ...

    private void MoveToNextCelebrity() 
    {
        ...

        _gameSettings.CelebrityNames = _celebrityNames;

        var intent = new Intent (this, typeof(GameRoundActivity));
        intent.PutExtra("GameSettings", _gameSettings);
        StartActivity (intent);

        ...
    }
}

GameRoundActivity.cs (where I'm passing the parcel to)

public class GameRoundActivity : Activity
{
    private GameSettings _gameSettings;

    protected override void OnCreate (Bundle savedInstanceState)
    {
        base.OnCreate (savedInstanceState);

        SetContentView (Resource.Layout.GameRound);

        _gameSettings = (Intent.Extras.GetParcelable ("GameSettings") as GameSettings);
    }
}

This is my first time developing an Android app, so it may well be that I've made a mistake somewhere in implementing the parcelling framework or have misunderstood it. Equally I've been looking at this code for so long that maybe I'm just missing a more general silly mistake :)

Thanks in advance!

1 Answers1

0

I switched to using a string array instead of a list and it's now working using Parcel.WriteStringArray() and Parcel.CreateStringArray().

Obviously this wouldn't be applicable in every situation though so I'm still interested in why this was happening!