Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Get rid of Parcelable Implemention

3.63/5 (4 votes)
4 Jan 2015CPOL 13.2K  
In this article we will implement a general Parcelable class and name it ParcelableEntity. Then all other entity class can extend it, then they will be parcelable too. So there is no need to implement Parcelable class for other classes.

Introduction

Implementing parcelable class for each entity that we want to pass between activities always was boring for me. So here we will implement it just one time for ever, then our entity classes will extend it and everything is done!

Majesty of reflections will help us.

Background

There are two solution for passing list between activities.

  1. Parcel
  2. Serialize

Here we focus on parcel.

Using the code

First we override writeToParcel method and rewrite it with reflection and looping over each field of entity.

Java
@Override
    public void writeToParcel(Parcel destination, int flags) {

        destination.writeString(this.getClass().getCanonicalName());

        for (Field field : this.getClass().getDeclaredFields()) {
            try {
                field.setAccessible(true);
                destination.writeValue(field.get(this));
            } catch (Exception err) {
                Log.w(TAG, err.toString());
            }

        }

    }

And then we implement Creator interface like below.

Java
public static final Creator CREATOR = new Creator() {
        public ParcelableEntity createFromParcel(Parcel source) {
            try {
                Object entity = Class.forName((source.readString())).newInstance();

                for (Field field : entity.getClass().getDeclaredFields()) {
                    try {
                        field.setAccessible(true);
                       field.set(entity, source.readValue(field.getType().getClassLoader()));

                    } catch (Exception err) {
                        Log.w(TAG, err.toString());
                    }
                }

                return (ParcelableEntity) entity;

            } catch (Exception err) {
                return null;
            }
        }

All done!

We save the child class name in the first line of our writeToParcel method because we need it in our createFromParcel method in order to create correct Object from our child class.

Java
//writeToParcel 
destination.writeString(this.getClass().getCanonicalName());

//createFromParcel 
Object entity = Class.forName((source.readString())).newInstance();

and all in one :

Java
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

import java.lang.reflect.Field;
import java.util.ArrayList;

public class ParcelableEntity implements Parcelable {
    private static final String TAG = "ParcelableEntity";

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

    @Override
    public void writeToParcel(Parcel destination, int flags) {

        destination.writeString(this.getClass().getCanonicalName());

        for (Field field : this.getClass().getDeclaredFields()) {
            try {
                field.setAccessible(true);
                if (field.getType().equals(java.util.List.class)) {
                    destination.writeList((ArrayList) field.get(this));
                } else
                    destination.writeValue(field.get(this));
            } catch (Exception err) {
                Log.w(TAG, err.toString());
            }

        }

    }

    public static final Creator CREATOR = new Creator() {
        public ParcelableEntity createFromParcel(Parcel source) {
            try {
                Object entity = Class.forName((source.readString())).newInstance();

                for (Field field : entity.getClass().getDeclaredFields()) {
                    try {
                        field.setAccessible(true);
                        if (field.getType().equals(java.util.List.class)) {
                            ArrayList list = new ArrayList();
                            source.readList(list, Class.forName(field.getDeclaringClass().getName()).getClassLoader());
                            field.set(entity, list);
                        } else
                            field.set(entity, source.readValue(field.getType().getClassLoader()));

                    } catch (Exception err) {
                        Log.w(TAG, err.toString());
                    }
                }

                return (ParcelableEntity) entity;

            } catch (Exception err) {
                return null;
            }
        }

        public ParcelableEntity[] newArray(int size) {
            return new ParcelableEntity[size];
        }
    };

}

and how to use our class :

1- Our entity class will extent above class :

Java
public class Book extends ParcelableEntity {

    public Long id;
    public String name;
}

2- Call destination activity :

Java
public void onClick(View view) {
        ArrayList<book> lstBook = new ArrayList<>();
        Book b1 = new Book();
        b1.id = 1L;
        b1.name = "test 1";
        lstBook.add(b1);
        Book b2 = new Book();
        b2.id = 2L;
        b2.name = "test 2";       
        lstBook.add(b2);

        Intent intent = new Intent(MainActivity.this, SecondActivity.class);
        intent.putParcelableArrayListExtra("TEST", lstBook);
        startActivity(intent);
    }
</book>

3- Geting extra in destination activity

Java
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Bundle extras = getIntent().getExtras();
        List<book> lstBook = extras.getParcelableArrayList("TEST");
    }
</book>

Thanks.

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)