I'm writing a RealmMigration, and after several different errors during that, I think I finally got it but now I'm getting io.realm.exceptions.RealmMigrationNeededException: Index not defined for field 'primaryKey'.
I saw something about needing to use table.addSearchIndex(), but even after adding that for each of my tables I'm still getting the exception.
Here is my Migration class.
Migration.java
public class Migration implements RealmMigration {
#Override
public long execute(Realm realm, long version) {
Timber.i("Current database version: " + version);
/**
* Version 1:
* Task:
* Remove boolean field completed
* Remove Date field completedDate
* Transaction:
* Add int field type
*/
if (version == 0) {
// Transaction
Table transactionTable = realm.getTable(Transaction.class);
transactionTable.addColumn(ColumnType.INTEGER, "type");
long transactionPrimaryKeyIndex = getIndexForProperty(transactionTable, "primaryKey");
long transactionTitleIndex = getIndexForProperty(transactionTable, "title");
long transactionPointsIndex = getIndexForProperty(transactionTable, "points");
long transactionDateIndex = getIndexForProperty(transactionTable, "date");
long transactionTypeIndex = getIndexForProperty(transactionTable, "type");
for (int i = 0; i < transactionTable.size(); i++) {
// Until now the only possible transaction was reward
transactionTable.setLong(transactionTypeIndex, i, Transaction.TYPE_REWARD);
}
// Task
Table taskTable = realm.getTable(Task.class);
// Go through and create Transactions for each completed Task
long taskPrimaryKeyIndex = getIndexForProperty(taskTable, "primaryKey");
long taskCompletedIndex = getIndexForProperty(taskTable, "completed");
long taskCompletedDateIndex = getIndexForProperty(taskTable, "completedDate");
long taskTitleIndex = getIndexForProperty(taskTable, "title");
long taskPointsIndex = getIndexForProperty(taskTable, "points");
for (int i = 0; i < taskTable.size(); i++) {
if (taskTable.getBoolean(taskCompletedIndex, i)) {
transactionTable.addEmptyRowWithPrimaryKey(transactionTable.getLong(transactionPrimaryKeyIndex, transactionTable.size() - 1) + 1);
long j = transactionTable.size() - 1; // The new row
transactionTable.setString(transactionTitleIndex, j, taskTable.getString(taskTitleIndex, i));
transactionTable.setLong(transactionPointsIndex, j, taskTable.getLong(taskPointsIndex, i));
transactionTable.setDate(transactionDateIndex, j, taskTable.getDate(taskCompletedDateIndex, i));
transactionTable.setLong(transactionTypeIndex, j, Transaction.TYPE_TASK);
}
}
// Finally, remove the columns we don't need any more
taskTable.removeColumn(getIndexForProperty(taskTable, "completed"));
taskTable.removeColumn(getIndexForProperty(taskTable, "completedDate"));
// https://realm.io/news/realm-java-0.82.0/
taskTable.addSearchIndex(taskPrimaryKeyIndex);
transactionTable.addSearchIndex(transactionPrimaryKeyIndex);
Table reminderTable = realm.getTable(Reminder.class);
Table rewardTable = realm.getTable(Reward.class);
reminderTable.addSearchIndex(getIndexForProperty(reminderTable, "primaryKey"));
rewardTable.add(getIndexForProperty(rewardTable, "primaryKey"));
version++;
}
return version;
}
private long getIndexForProperty(Table table, String name) {
for (int i = 0; i < table.getColumnCount(); i++) {
if (table.getColumnName(i).equals(name)) {
return i;
}
}
return -1;
}
}
Task.java
public class Task extends RealmObject {
#PrimaryKey
private long primaryKey;
private String title;
private String description;
private int points;
private boolean hasReminders;
private RealmList<Reminder> reminders;
public static long getNextPrimaryKey(Realm realm) {
RealmResults<Task> tasks = realm.where(Task.class).findAllSorted("primaryKey");
if (tasks.size() == 0) return 0;
return tasks.last().getPrimaryKey() + 1;
}
// Getters and setters
}
Transaction.java
public class Transaction extends RealmObject {
public static final int TYPE_TASK = 0;
public static final int TYPE_REWARD = 1;
#PrimaryKey
private long primaryKey;
private String title;
private int points;
private Date date;
private int type;
public static long getNextPrimaryKey(Realm realm) {
if (realm != null) {
RealmResults<Transaction> transactions = realm.where(Transaction.class).findAllSorted("primaryKey");
if (transactions.size() == 0) return 0;
return transactions.last().getPrimaryKey() + 1;
} else {
return 0;
}
}
}
// Getters and setters
}
It is because you are removing two columns in the task table before adding the index. That means that the index you calculated in the beginning is no longer valid.
Related
I am having a problem incrementing my integer variable after a certain condition is met in Android Programming. Why is it not incrementing?
The code below are implemented on an ImageButton which lies a class (Activity) called Product.
int count = 1;
List<Item> prod = ShoppingCart.getInstance().getProducts();
// if arraylist is null --> add a product
if(prod != null && prod.isEmpty()){
ShoppingCart.getInstance().addItem(new Item(
namePureString,
manufacturePureString,
pricePureString,
"",
count
));
Toast.makeText(getApplicationContext(), namePureString + " Added To Cart", Toast.LENGTH_SHORT).show();
}else {
for (Item products : ShoppingCart.getInstance().myProducts) {
// here i am checking if the product exists, if it does --> count has to increment
if (products.getManufacture().equals(manufacturePureString)) {
count += count;
Toast.makeText(getApplicationContext(), "You Added This Product\nQuantity Will Increase",
Toast.LENGTH_SHORT).show();
ShoppingCart.getInstance().setItemExists(new Item(
namePureString,
manufacturePureString,
pricePureString,
"",
count
));
} else {
ShoppingCart.getInstance().addItem(new Item(
namePureString,
manufacturePureString,
pricePureString,
"",
count
));
}
}
This is my Singleton class, in which I call its methods:
public class ShoppingCart {
private static final String TAG = "Products: ";
private static ShoppingCart ourInstance = null;
public ArrayList<Item> myProducts = new ArrayList<>();
private ShoppingCart() {
}
public static ShoppingCart getInstance() {
// if object instance does not exist create a new one and use that one only
if ( ourInstance == null){
ourInstance = new ShoppingCart();
}
return ourInstance;
}
public void addItem(Item item){
ourInstance.myProducts.add(item);
}
public void setItemExists(Item item) {
int itemIndex = ourInstance.myProducts.indexOf(item);
if (itemIndex != -1) {
ourInstance.myProducts.set(itemIndex, item);
}
}
public List<Item> getProducts(){
return this.myProducts;
}
}
count++ is the same as count = count + 1 and not count += count in your Code. Count += count adds the amount of count on top of the value of count.
So to increment add this:
count = count + 1;
//or
count++;
Try
int count = 0;
count = count + 1;
Log.d("Answer: ",count);
Instead of count += count; try with count++;
I'd like to use ExoPlayer2 with playlists having possibility to dinamically change the tracks (add or remove them from playlist) and change the loop settings.
Since ConcatenatingMediaSource has static arrays (and not lists), I'm implementing a DynamicMediaSource, like Concatenating one but with lists instead of arrays and one mode method addSource to add one more media source to the list.
public void addSource(MediaSource mediaSource) {
this.mediaSources.add(mediaSource);
duplicateFlags = buildDuplicateFlags(this.mediaSources);
if(!mediaSources.isEmpty())
prepareSource(mediaSources.size() -1);
else
prepareSource(0);
}
When I invoke addSource
MediaSource ms = buildMediaSource(mynewuri, null);
mediaSource.addSource(ms);
the track is added to the arrays but it seems something is missing because I always obtain ArrayOutOfBoundsException in createPeriod method.
In createPeriod the method
mediaSources.get(sourceIndex)...
is trying to access the index = mediaSources.size().
Can you help me?
I eventually managed it.
It was my fault during the conversion from arrays to lists.
I had to use SparseArrays for timelines and manifests and everything began to work.
In the DynamicMediaSource simply set the following types:
private final List<MediaSource> mediaSources;
private final SparseArray<Timeline> timelines;
private final SparseArray<Object> manifests;
private final Map<MediaPeriod, Integer> sourceIndexByMediaPeriod;
private SparseArray<Boolean> duplicateFlags;
you have to use sparse arrays to set the proper values into the timelines and manifests in the method
private void handleSourceInfoRefreshed(int sourceFirstIndex, Timeline sourceTimeline,
Object sourceManifest) {
// Set the timeline and manifest.
timelines.put(sourceFirstIndex, sourceTimeline);
manifests.put(sourceFirstIndex, sourceManifest);
// Also set the timeline and manifest for any duplicate entries of the same source.
for (int i = sourceFirstIndex + 1; i < mediaSources.size(); i++) {
if (mediaSources.get(i).equals(mediaSources.get(sourceFirstIndex))) {
timelines.put(i, sourceTimeline);
manifests.put(i, sourceManifest);
}
}
for(int i= 0; i<mediaSources.size(); i++){
if(timelines.get(i) == null){
// Don't invoke the listener until all sources have timelines.
return;
}
}
timeline = new DynamicTimeline(new ArrayList(asList(timelines)));
listener.onSourceInfoRefreshed(timeline, new ArrayList(asList(manifests)));
}
Here is the complete code of DynamicMediaSource class:
public final class DynamicMediaSource implements MediaSource {
private static final String TAG = "DynamicSource";
private final List<MediaSource> mediaSources;
private final List<Timeline> timelines;
private final List<Object> manifests;
private final Map<MediaPeriod, Integer> sourceIndexByMediaPeriod;
private SparseArray<Boolean> duplicateFlags;
private Listener listener;
private DynamicTimeline timeline;
/**
* #param mediaSources The {#link MediaSource}s to concatenate. It is valid for the same
* {#link MediaSource} instance to be present more than once in the array.
*/
public DynamicMediaSource(MediaSource... mediaSources) {
this.mediaSources = new ArrayList<MediaSource>(Arrays.asList(mediaSources));
timelines = new ArrayList<Timeline>();
manifests = new ArrayList<Object>();
sourceIndexByMediaPeriod = new HashMap<>();
duplicateFlags = buildDuplicateFlags(this.mediaSources);
}
public void addSource(MediaSource mediaSource) {
this.mediaSources.add(mediaSource);
duplicateFlags = buildDuplicateFlags(this.mediaSources);
/*if(!mediaSources.isEmpty())
prepareSource(mediaSources.size() -1);
else
prepareSource(0);*/
}
#Override
public void prepareSource(Listener listener) {
this.listener = listener;
for (int i = 0; i < mediaSources.size(); i++) {
prepareSource(i);
/*if (duplicateFlags.get(i) == null || !duplicateFlags.get(i)) {
final int index = i;
mediaSources.get(i).prepareSource(new Listener() {
#Override
public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
handleSourceInfoRefreshed(index, timeline, manifest);
}
});
}*/
}
}
private void prepareSource(int sourceindex) {
if (duplicateFlags.get(sourceindex) == null || !duplicateFlags.get(sourceindex)) {
final int index = sourceindex;
mediaSources.get(sourceindex).prepareSource(new Listener() {
#Override
public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
handleSourceInfoRefreshed(index, timeline, manifest);
}
});
}
}
#Override
public void maybeThrowSourceInfoRefreshError() throws IOException {
for (int i = 0; i < mediaSources.size(); i++) {
if (duplicateFlags.get(i) == null || !duplicateFlags.get(i)) {
mediaSources.get(i).maybeThrowSourceInfoRefreshError();
}
}
}
#Override
public MediaPeriod createPeriod(int index, Callback callback, Allocator allocator,
long positionUs) {
int sourceIndex = timeline.getSourceIndexForPeriod(index);
int periodIndexInSource = index - timeline.getFirstPeriodIndexInSource(sourceIndex);
MediaPeriod mediaPeriod = mediaSources.get(sourceIndex).createPeriod(periodIndexInSource, callback,
allocator, positionUs);
sourceIndexByMediaPeriod.put(mediaPeriod, sourceIndex);
return mediaPeriod;
}
#Override
public void releasePeriod(MediaPeriod mediaPeriod) {
int sourceIndex = sourceIndexByMediaPeriod.get(mediaPeriod);
sourceIndexByMediaPeriod.remove(mediaPeriod);
mediaSources.get(sourceIndex).releasePeriod(mediaPeriod);
}
#Override
public void releaseSource() {
for (int i = 0; i < mediaSources.size(); i++) {
if (duplicateFlags.get(i) == null || !duplicateFlags.get(i)) {
mediaSources.get(i).releaseSource();
}
}
}
private void handleSourceInfoRefreshed(int sourceFirstIndex, Timeline sourceTimeline,
Object sourceManifest) {
// Set the timeline and manifest.
timelines.add(sourceFirstIndex, sourceTimeline);
manifests.add(sourceFirstIndex, sourceManifest);
// Also set the timeline and manifest for any duplicate entries of the same source.
for (int i = sourceFirstIndex + 1; i < mediaSources.size(); i++) {
if (mediaSources.get(i).equals(mediaSources.get(sourceFirstIndex))) {
timelines.add(i, sourceTimeline);
manifests.add(i, sourceManifest);
}
}
for (Timeline timeline : timelines) {
if (timeline == null) {
// Don't invoke the listener until all sources have timelines.
return;
}
}
timeline = new DynamicTimeline(new ArrayList(timelines));
listener.onSourceInfoRefreshed(timeline, new ArrayList(manifests));
}
private static SparseArray<Boolean> buildDuplicateFlags(List<MediaSource> mediaSources) {
SparseArray<Boolean> duplicateFlags = new SparseArray<Boolean>();
IdentityHashMap<MediaSource, Void> sources = new IdentityHashMap<>(mediaSources.size());
for (int i = 0; i < mediaSources.size(); i++) {
MediaSource mediaSource = mediaSources.get(i);
if (!sources.containsKey(mediaSource)) {
sources.put(mediaSource, null);
} else {
duplicateFlags.setValueAt(i, true);
}
}
return duplicateFlags;
}
/**
* A {#link Timeline} that is the concatenation of one or more {#link Timeline}s.
*/
private static final class DynamicTimeline extends Timeline {
private final List<Timeline> timelines;
private final List<Integer> sourcePeriodOffsets;
private final List<Integer> sourceWindowOffsets;
public DynamicTimeline(List<Timeline> timelines) {
List<Integer> sourcePeriodOffsets = new ArrayList<>();
List<Integer> sourceWindowOffsets = new ArrayList<>();
int periodCount = 0;
int windowCount = 0;
for (Timeline timeline : timelines) {
periodCount += timeline.getPeriodCount();
windowCount += timeline.getWindowCount();
sourcePeriodOffsets.add(periodCount);
sourceWindowOffsets.add(windowCount);
}
this.timelines = timelines;
this.sourcePeriodOffsets = sourcePeriodOffsets;
this.sourceWindowOffsets = sourceWindowOffsets;
}
#Override
public int getWindowCount() {
return sourceWindowOffsets.get(sourceWindowOffsets.size() - 1);
}
#Override
public Window getWindow(int windowIndex, Window window, boolean setIds) {
int sourceIndex = getSourceIndexForWindow(windowIndex);
int firstWindowIndexInSource = getFirstWindowIndexInSource(sourceIndex);
int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex);
timelines.get(sourceIndex).getWindow(windowIndex - firstWindowIndexInSource, window, setIds);
window.firstPeriodIndex += firstPeriodIndexInSource;
window.lastPeriodIndex += firstPeriodIndexInSource;
return window;
}
#Override
public int getPeriodCount() {
return sourcePeriodOffsets.get(sourcePeriodOffsets.size() - 1);
}
#Override
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
int sourceIndex = getSourceIndexForPeriod(periodIndex);
int firstWindowIndexInSource = getFirstWindowIndexInSource(sourceIndex);
int firstPeriodIndexInSource = getFirstPeriodIndexInSource(sourceIndex);
timelines.get(sourceIndex).getPeriod(periodIndex - firstPeriodIndexInSource, period, setIds);
period.windowIndex += firstWindowIndexInSource;
if (setIds) {
period.uid = Pair.create(sourceIndex, period.uid);
}
return period;
}
#Override
public int getIndexOfPeriod(Object uid) {
if (!(uid instanceof Pair)) {
return C.INDEX_UNSET;
}
Pair<?, ?> sourceIndexAndPeriodId = (Pair<?, ?>) uid;
if (!(sourceIndexAndPeriodId.first instanceof Integer)) {
return C.INDEX_UNSET;
}
int sourceIndex = (Integer) sourceIndexAndPeriodId.first;
Object periodId = sourceIndexAndPeriodId.second;
if (sourceIndex < 0 || sourceIndex >= timelines.size()) {
return C.INDEX_UNSET;
}
int periodIndexInSource = timelines.get(sourceIndex).getIndexOfPeriod(periodId);
return periodIndexInSource == C.INDEX_UNSET ? C.INDEX_UNSET
: getFirstPeriodIndexInSource(sourceIndex) + periodIndexInSource;
}
private int getSourceIndexForPeriod(int periodIndex) {
return Util.binarySearchFloor(sourcePeriodOffsets, periodIndex, true, false) + 1;
}
private int getFirstPeriodIndexInSource(int sourceIndex) {
return sourceIndex == 0 ? 0 : sourcePeriodOffsets.get(sourceIndex - 1);
}
private int getSourceIndexForWindow(int windowIndex) {
return Util.binarySearchFloor(sourceWindowOffsets, windowIndex, true, false) + 1;
}
private int getFirstWindowIndexInSource(int sourceIndex) {
return sourceIndex == 0 ? 0 : sourceWindowOffsets.get(sourceIndex - 1);
}
}
}
i'm using custom class to store user specific information class is as under:
using UnityEngine;
using System.Collections;
public class RoomPlayerInfo {
private int minutes;
private int seconds;
private int miliSecond;
private string userName;
public int Minutes{
get{ return minutes; }
set{ minutes = value;}
}
public int Seconds{
get{ return seconds; }
set{ seconds = value; }
}
public string UserName{
get{ return userName; }
set{ userName = value; }
}
public int MiliSecond{
get{ return miliSecond;}
set{ miliSecond = value;}
}
}
i'm adding user at runtime in a list:
private List<RoomPlayerInfo> listRoomPlayerInfo = new List<RoomPlayerInfo> ();
RoomPlayerInfo rPI = new RoomPlayerInfo ();
rPI.Minutes = diff.Minutes;
rPI.Seconds = diff.Seconds;
rPI.MiliSecond = diff.Milliseconds;
rPI.UserName = sfs.MySelf.Name;
listRoomPlayerInfo.Add (rPI);
When i'm going to remove a player at runtime, it only remove the currentPlayer on each device, mean on each device remove the own player of such device, but i'm going to remove the player which take max time in game..
How i can done my job ???
void RemovePlayer()
{
int i = 0;
int removePlayerIndex = 0;
if (listRoomPlayerInfo != null) {
string playerID = listRoomPlayerInfo [i].UserName;
for (; i < listRoomPlayerInfo.Count -1; i++) {
if (listRoomPlayerInfo [i + 1].Minutes >= listRoomPlayerInfo [i].Minutes && listRoomPlayerInfo [i + 1].Seconds > listRoomPlayerInfo [i].Seconds && listRoomPlayerInfo[i+1].MiliSecond > listRoomPlayerInfo[i].MiliSecond) {
playerID = listRoomPlayerInfo [i + 1].UserName;
removePlayerIndex = i + 1;
}
}
removeUserName.text = playerID + " Remove from room...";
listRoomPlayerInfo.Remove (listRoomPlayerInfo [removePlayerIndex]);
}
}
In String.CASE_INSENSITIVE_ORDER.compare(String, String), where is the function compare(String, String) defined?
The String.CASE_INSENSITIVE_ORDER is an implementation of the Comparator Interface. This is implemented within the String class. Here is the whole Comparator from the String.java file.
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
implements Comparator<String>, java.io.Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 8575799808933029326L;
public int compare(String s1, String s2) {
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
c1 = Character.toLowerCase(c1);
c2 = Character.toLowerCase(c2);
if (c1 != c2) {
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2;
}
}
CASE_INSENSETIVE_ORDER is a static field of String class of type Comperator.
it comtains the compare() method
See this
I can't see the error, I'm having this problem for a long time already... My parcelable class crashes if it is recreated, but I can't find the problem...
I checked the order of writing/reading data.
I checked the functions I use (direct reading/writing vs my custum null save functions)
I marked the line in the first code block that created following exception: java.lang.ArrayIndexOutOfBoundsException: length=5; index=5
SHORT CODE
private Set<ContactType> mMatchesDataLoaded = new HashSet<ContactType>();
saving the set
dest.writeInt(mMatchesDataLoaded.size());
Iterator<ContactType> it = mMatchesDataLoaded.iterator();
while (it.hasNext())
dest.writeInt(it.next().ordinal());
reading the set
int count = source.readInt();
for (int i = 0; i < count; i++)
// ---------------------------------------------------------------------------
// next line produces EXCEPTION!!! java.lang.ArrayIndexOutOfBoundsException: length=5; index=5
// ---------------------------------------------------------------------------
mMatchesDataLoaded.add(ContactType.values()[source.readInt()]);
FULL CODE
I can't see any problems or rather where the problem is...
public class ContactPhone implements Parcelable
{
public static enum ContactType
{
WhatsApp,
Viber,
GooglePlus,
Twitter,
Instagram
}
private boolean mIsUserProfile = false;
private boolean mHasImage;
private int mId;
private long mRawId;
private String mName = null;
private List<PhoneNumber> mNumbers = new ArrayList<PhoneNumber>();
private DBPhoneContact mDBContact = null;
private Set<ContactType> mMatchesDataLoaded = new HashSet<ContactType>();
private HashMap<ContactType, List<BaseMatchContact>> mMatchesData = new HashMap<ContactType, List<BaseMatchContact>>();
// ----------------------
// Parcelable
// ----------------------
#Override
public void writeToParcel(Parcel dest, int flags)
{
ParcelBundleUtils.writeBoolean(dest, mIsUserProfile);
ParcelBundleUtils.writeBoolean(dest, mHasImage);
ParcelBundleUtils.writeIntegerNullSafe(dest, mId);
ParcelBundleUtils.writeLongNullSafe(dest, mRawId);
ParcelBundleUtils.writeStringNullSafe(dest, mName);
dest.writeList(mNumbers);
ParcelBundleUtils.writeLongNullSafe(dest, mDBContact != null ? mDBContact.getId() : null);
// save set
dest.writeInt(mMatchesDataLoaded.size());
Iterator<ContactType> it = mMatchesDataLoaded.iterator();
while (it.hasNext())
dest.writeInt(it.next().ordinal());
// save HashMap
dest.writeInt(mMatchesData.size());
for (Map.Entry<ContactType, List<BaseMatchContact>> entry : mMatchesData.entrySet())
{
dest.writeInt(entry.getKey().ordinal());
dest.writeInt(entry.getValue().size());
for (int i = 0; i < entry.getValue().size(); i++)
dest.writeParcelable(entry.getValue().get(i), 0);
}
}
public void readFromParcel(Parcel source)
{
mIsUserProfile = ParcelBundleUtils.readBoolean(source);
mHasImage = ParcelBundleUtils.readBoolean(source);
mId = ParcelBundleUtils.readIntegerNullSafe(source);
mRawId = ParcelBundleUtils.readLongNullSafe(source);
mName = ParcelBundleUtils.readStringNullSafe(source);
source.readList(mNumbers, PhoneNumber.class.getClassLoader());
Long id = ParcelBundleUtils.readLongNullSafe(source);
mDBContact = null;
if (id != null)
mDBContact = MainApp.getDS().getDBPhoneContactDao().load(id);
// read set
int count = source.readInt();
for (int i = 0; i < count; i++)
// ---------------------------------------------------------------------------
// next line produces EXCEPTION!!! java.lang.ArrayIndexOutOfBoundsException: length=5; index=5
// ---------------------------------------------------------------------------
mMatchesDataLoaded.add(ContactType.values()[source.readInt()]);
// read HashMap
count = source.readInt();
for (int i = 0; i < count; i++)
{
ContactType type = ContactType.values()[source.readInt()];
Class<?> clazz = BaseDef.getMatchClass(type);
// L.d(this, "Classloader: " + clazz.getName() + " type: " + type.name());
int size = source.readInt();
List<BaseMatchContact> list = new ArrayList<BaseMatchContact>();
for (int j = 0; j < size; j++)
list.add((BaseMatchContact) source.readParcelable(clazz.getClassLoader()));
mMatchesData.put(type, list);
}
}
}
The PhoneNumber class implements parcelable and is quite simple and read/writes like following:
#Override
public void writeToParcel(Parcel dest, int flags)
{
ParcelBundleUtils.writeStringNullSafe(dest, mName);
ParcelBundleUtils.writeStringNullSafe(dest, mNormNumber);
ParcelBundleUtils.writeStringNullSafe(dest, mNumber);
}
public void readFromParcel(Parcel source)
{
mName = ParcelBundleUtils.readStringNullSafe(source);
mNormNumber = ParcelBundleUtils.readStringNullSafe(source);
mNumber = ParcelBundleUtils.readStringNullSafe(source);
}
And here are my helper functions:
public static void writeBoolean(Parcel p, boolean b)
{
p.writeByte((byte) (b ? 1 : 0));
}
public static boolean readBoolean(Parcel p)
{
return p.readByte() == 1;
}
public static void writeStringNullSafe(Parcel p, String s)
{
p.writeByte((byte) (s != null ? 1 : 0));
if (s != null)
p.writeString(s);
}
public static void writeIntegerNullSafe(Parcel p, Integer i)
{
p.writeByte((byte) (i != null ? 1 : 0));
if (i != null)
p.writeInt(i);
}
public static void writeLongNullSafe(Parcel p, Long l)
{
p.writeByte((byte) (l != null ? 1 : 0));
if (l != null)
p.writeLong(l);
}
public static void writeDoubleNullSafe(Parcel p, Double d)
{
p.writeByte((byte) (d != null ? 1 : 0));
if (d != null)
p.writeDouble(d);
}
public static void writeParcelableNullSafe(Parcel p, Parcelable d, int flags)
{
p.writeByte((byte) (d != null ? 1 : 0));
if (d != null)
p.writeParcelable(d, flags);
}
public static String readStringNullSafe(Parcel p)
{
boolean isPresent = p.readByte() == 1;
return isPresent ? p.readString() : null;
}
public static Integer readIntegerNullSafe(Parcel p)
{
boolean isPresent = p.readByte() == 1;
return isPresent ? p.readInt() : null;
}
public static Long readLongNullSafe(Parcel p)
{
boolean isPresent = p.readByte() == 1;
return isPresent ? p.readLong() : null;
}
public static Double readDoubleNullSafe(Parcel p)
{
boolean isPresent = p.readByte() == 1;
return isPresent ? p.readDouble() : null;
}
#SuppressWarnings("unchecked")
public static <T extends Parcelable> T readParcelableNullSafe(Parcel p, ClassLoader classLoader)
{
boolean isPresent = p.readByte() == 1;
return isPresent ? (T) p.readParcelable(classLoader) : null;
}
int count = source.readInt(); // index is raised + 1
for (int i = 0; i < count; i++)
mMatchesDataLoaded.add(ContactType.values()[source.readInt()]); // index is raised by 1, starting with 1!
you loop from 0 to 4, but source.readInt() was already called once, so you called it 5 times in total.
ContactType contains 5 values, from index 0 to index 4. You are trying to access the index 5, which does not exist.
mMatchesDataLoaded.add(ContactType.values()[source.readInt()]);
source.readInt() gives you a 5, try to figure out, with debug, why does it contain this value.
My guess is that writeToParcel writes this 5, try to inspect mMatchesDataLoaded which maybe contains some additional unwanted data.