22-Apr-13 (Created: 22-Apr-13) | More in 'Parse Cloud'

Enhancing Parse with Parcelables: An article

This article talks about how to parcel parse objects so that the target activities can receive parse objects through intents. Parse objects don't natively support any form of serialization. So the approach presented here is an approximation of sending parse object through a parcelable and would meet most simple needs. (Please note that this is a draft)

In a previous article I documented the basic features of parse. I showed you how to create an account with parse and use that account to sign up users and store obejects in the cloud on behalf of those users. I have also showed you the basic mechanism to query parse objects.

In this article I want to cover two topics. First is the need to pass Parse objects as parcelables through intent extras. The second is the ability to query for parse objects based on their relationship to other parse objects.

Let's talk about the first need in a bit more detail. If you recall the dictionary like application I introduced to explain parse, there are two types of objects that are specific to that application. Words and their Meanings. Each word can have any number of meanings provided by various users. I wanted to create a screen where I show the meanings for a given word. As it turned out this a bit tricky because of Android and also Parse.

Lets understand what is tricky about displaying the screen that shows meanings for a given word. Ideally I will choose a word parse object and pass it to the activity that lists meanings for that word. Once I have a word object in the receiving Word meanings activity, I can run a query on word meanings whose parent word is the word that is passed in.

However Android SDK has a stipulation where you cannot pass references to in memory objects to another activity willy-nilly. Only certain ceremonial objects could be done this way (For example such as those implementing IBinder). And Word and Word Meaning objects are the least bit ceremonial! They are just expected to be plain java objects holding a few attributes. So in Android you pass data as opposed to object references to other activities through intent extras. So we have to figure out how to pass a word parse object through an intent to an activity that shows word meanings.

You can try to do the following


ParseObject wordObject;
Intent i = new Intent(this,MeaningsListActivity.classname);
i.putExtra("word-parse-object", wordObject);
this.startActivity(i);

In the code above the variable "this" points to the current activity. If this were to be successful then the receiving activity can retrieve the word object like this


Intent i = this.getIntent();
ParseObject parceledWord = (ParseObject)i.getParcelableExtra();

However for this to work the type ParseObject needs to implement the Android SDK interface Parcelable and it does not!! So this article takes the subject from the previous article and extends it to explain the following two things


1. How do you pass a ParseObject through intents
2. How do you use the parceled ParseObject in a query to retrieve its children

Before we start with fully exploring these two topics, following the pattern used in the first article, let us show you the user experience where the previous application is extended with additional screens for the meanings of words. This I hope will give a context to what I am trying to do in concrete terms.

User Experiece of Word Meaning Activities

Lets start with the picture of the list of words that was shown in the previous article below.

List of Words Activity

What you see here is a list of words. By tapping the "Meanings" button you will be taken to the activity that shows the meanings for this word if there are any. Here is that screen below

word meanings list activity

What you see here is a list of available meanings for this word. Clearly this activity needs a word object to paint itself. So when I implement this activity later I will show you how parcelables play a role. This activity also shows a button to create a meaning for the current word. Here is that screen to create the word meaning

Creating a Meaning for a Word

Although this screen is quite simple we also need to solve the issue of passing the parent word object as a parcelable so that the meaning I create belongs to the right parse word object. Also because this screen is invoked from the word meanings list screen, we need to parcel a word parse object that is already passed in parceled. So any solution I am suggesting should work passing that object multiple times as intent extra.

Let me turn now to restate the parcelable in more detail and cover the theory behind Parcels and Parcelables in the Android SDK before implementing the solution.

Passing ParseObjects as Parcelables

To send a ParseObject through an intent is to make it Parcelable. But ParseObject is a type that is already defined and frozen by the Parse SDK. To further complicate the matters the ParseObject is not only not-parcelable but also not serializable either. It also cannot be converted to a JSON string. Had it bean serializable or converted to a json string we could have passed it through the parcelable in that form.

So here is a possible option. Read all the values from a parse object and put them in a hashmap ourselves and then either serialize or convert that hashmap to a string which can then be passed throught he parcelable. On the other side take that paceled hashmap and construct a parse object to the extent that we can construct it as the original parse object. It is possible that the original parse object may have an internal state that we are not aware of and hence cannot be replicated as is.

I didn't take that approach of mapping Parse objects into hashmaps for transport. One reason is that in the previous article I already have an object that is wrapping the original parse object. it is called the ParseObjectWrapper.

So I thought I would rather use this wrapper to go across as a parcelable. Except on the other side when this ParseWrapperObject is recreated it will have a recreated ParseObject at its core and not the original parse object.

The methods on the ParseObjectWrapper can detect that the embedded ParseObject is a cloned one and do the adjustments as needed to give the impression that you are as close as possible to dealing with a real parse object.

In addition the end user objects such as Word and WordMeaning are already extending the ParseObjectWrapper, so it is easier to recreate them from ParseObjectWrapper.

But again I have started with ParseObjectWrapper and it seem to be doable at that level and so the research to see if the hashmaps are better in otherways was not done. I don't see those advantages too apparent at the moment nor have a possibility that they may be better so I will stick to using ParseObjectWrapper as a vehicle to parcelables.

Also as indicated in the previous article if you were to use reflection and interface based approaches such as ParseFacade or BAASFacade you may have better options. I will leave that research to you.

So I am going to stick to extending the ParseObjectWrapper with parcelable support. Let's cover the theory behind parcelables and then dig into the code to see how we make the ParseObjectWrapper parcellable.

What is a Parcelable?

In Android Parcels are used to pass messages between processes. It is an IPC (Inter Process Communication) mechanism in Android. A Parcel as a result is a stream of message data that can be communicated and stored either in real time or at a later point through store and forward between processes.

A Parcel can contain data that is flattened on one side from objects and then unflattened on the other side back into objects. More interestingly it can be used also to carry object references or proxies to services or file streams. To quickly enumerate what a Pacel contain, here is a list


Primitives
arrays (4 byte length + data)
Objects that implement the Parcelable interface
Bundles (key value pairs where values reflect any of the above)
Proxy objects using IBinder interfaces
File descriptor objects that are proxies

You can learn more about Parcels and Parcelables at the Android SDk link below

http://developer.android.com/reference/android/os/Parcel.html

When an object implements the parcelable interface, the object is promising the Android SDK that it knows how to write itself to a Parcel field by field. Such a parcelable object also knows how to create and read itself field by field from the Parcel.

A Simple Example of implementing a Parcelable

Let us consider a simple object and see how it goes about implementing parcelable if it wants to be transported across


public class User
implements Parcelable
{
    //Add more field types later
    public String userid;
    public String username;
    
    public User(String inuserid, String inusername)
    {
        userid = inuserid;
        username = inusername;
    }
    public static final Parcelable.Creator<User> CREATOR
        = new Parcelable.Creator<User>() {
            public User createFromParcel(Parcel in) {
                return new User(in);
            }
            
            public User[] newArray(int size) {
                return new User[size];
            }
    }; //end of creator

    //
    @Override
    public int describeContents() {
        return 0;
    }
    
    public User(Parcel in)
    {
        userid = in.readString();
        username = in.readString();
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) 
    {
        dest.writeString(userid);
        dest.writeString(username);
    }
}//eof-class

This is a class called a User and it has just two fields. username and userid. When this class implements the Parcelable interface it needs to be aware of three key ideas


1. Understand to see if it needs to handle describeContents()
2. Know how to read and write its constituent attributes
3. Understand flags to alter the behavior of what and how to write if needed

Describing Contents and File Descriptors

Apparently for Android SDK it is important to know if a Parceled object contains file descriptors. Because file descriptors may be unique to a process they may not make sense in their raw form to another process. So when Android does the IPC mechanism it treats that parceled object appropriately. The way an object declares that it has file descriptors is to override the describeContents() method and return the pre defined value of


CONTENTS_FILE_DESCRIPTOR 

In our case our object does not even remotely deal with file descriptors so we safely return a zero indicating that we don't need any special handling by the OS. If you want to see how to work with objects containing file descriptors refer to the source code of the Android SDK class ParcelFileDescriptor.

Reading and Writing Members to a Parcel

The second responsibility of the parcelable class is to read and write its members from and to the parcel object. If you see the writeToParcel() method you see that we are writing the string objects to the parcel stream. Similarly to read the members of the User class take a look at the constructor User(Parcel p). This constructor simply reads the values back into its local variables.

Unlike the writeParcel() method there is no equivalent readParcel() in the User class. Instead the Android SDK requires that the class implementing the parcelable interface provide a static reference to a CREATOR object that knows how to instantiate objects of the specific type such as User in our case. This CREATOR object has the createFromParcel() method that is responsible for instantiating the User object by calling its appropriate constructor that takes ths parcel object as input.

The Write time Parcelable Flags

Now to the finer point of parcelable flag. When a client writes an object to a parcel using the parcel.writeParcelable(Parcelable p, int flags) the client can pass flags so that the parcelable that is being written can alter what to write.

The only flag defined and recognized by the android SDK is


PARCELABLE_WRITE_RETURN_VALUE

To know if a Parcelable does anything differently when this flag is passed is only known from its documentation. For example the ParcelableFileDescriptor uses this flag and if passed in it will close the file descriptor and merely passes its value through the parcel. In our case here the User class does not use this flag at all.

Another recommendation from the API is that if your parcelable represents a stateful object like say a file descriptor or a reference to a service, you may want to reclaim the resources and just pass the proxies or vlaues to those underlying resource. In such cases Android API recommends this is a good use to recognize this flag.

So while parcelling core android objects pay attention to the documentation of those objects to see if they honor this flag and if the behavior would be affected by this flag.

In the case of the User example there is really no reason to recognize or react to this flag.

So for most cases when we are writing parcelables you can always return 0 for describeContents() and ignore the flags while writing to parcelables.

Now that you have an understanding what parcelables are and how parcelables work let's see how we go about implementing the ParseObjectWrapper as a parcelable.

ParseObjectWrapper

Let me present the source code for the ParseObjectWrapper first and then I will discuss the relevant portions subsequently.


public class ParseObjectWrapper
implements Parcelable
{
    public static String f_createdAt = "createdAt";
    public static String f_createdBy = "createdBy";
    
    public static String f_updatedAt = "updatedAt";
    public static String f_updatedBy = "updatedBy";
    
    //The parse object that is being wrapped
    public ParseObject po;
    
    //Constructors
    //Use this when you are creating a new one from scratch
    public ParseObjectWrapper(String tablename)    {
        po = new ParseObject(tablename);
        po.put(f_createdBy, ParseUser.getCurrentUser());
    }
    //Use this to create proper shell
    //For example you can do this in parcelable
    public ParseObjectWrapper(String tablename, String objectId)
    {
        po = ParseObject.createWithoutData(tablename, objectId);
    }
    
    //Use this when you are creating from an exsiting parse obejct
    public ParseObjectWrapper(ParseObject in)
    {
        po = in;
    }
    
    //To create derived objects like Word using the 
    //ParseObjectWrapper that is unparceled
    public ParseObjectWrapper(ParseObjectWrapper inPow)
    {
        //Parseobject underneath
        po = inPow.po;
        
        //parseobject essentials if it has it
        poe = inPow.poe;
    }
    
    //Accessors
    public ParseObject getParseObject() { return po; }
    String getTablename(){return po.getClassName();    }
    public ParseUser getCreatedBy(){return po.getParseUser(f_createdBy);}
    public void setCreatedBy(ParseUser in){po.put(f_createdBy, in);}
    public void setUpdatedBy(){po.put(f_updatedBy, ParseUser.getCurrentUser());}
    public ParseUser getLastUpdatedBy(){return   
                ParseUser)po.getParseObject(f_updatedBy);    }
    
    //Parcelable stuff
    @Override
    public int describeContents() {
        return 0;
    }
    public static final Parcelable.Creator<ParseObjectWrapper> CREATOR
        = new Parcelable.Creator<ParseObjectWrapper>() {
            public ParseObjectWrapper createFromParcel(Parcel in) {
                return create(in);
            }
            public ParseObjectWrapper[] newArray(int size) {
                return new ParseObjectWrapper[size];
            }
    }; //end of creator
    
    @Override
    public void writeToParcel(Parcel parcel, int flags) 
    {
        //Order: tablename, objectId, fieldlist, field values, essentials
        
        //write the tablename
        parcel.writeString(this.getTablename());
        
        //write the object id
        parcel.writeString(this.po.getObjectId());
        
        //write the field list and write the field names
        List<ValueField> fieldList = getFieldList();
        //See how many
        int i = fieldList.size();
        parcel.writeInt(i);
        
        //write each of the field types
        for(ValueField vf: fieldList)      {
            parcel.writeParcelable(vf, flags);
        }
        
        //You need to write the field values now
        FieldTransporter ft = new FieldTransporter(this.po,parcel,FieldTransporter.DIRECTION_FORWARD);
        for(ValueField vf: fieldList)      {
            //This will write the field from parse object to the parcel
            ft.transfer(vf);
        }
        
        //get the essentials and write to the parcel
        ParseObjectEssentials lpoe = this.getEssentials();
        parcel.writeParcelable(lpoe, flags);
    }
    //
    private static ParseObjectWrapper create(Parcel parcel)
    {
        //Order: tablename, objectid, fieldlist, field values, essentials
        
        String tablename = parcel.readString();
        String objectId = parcel.readString();
        
        ParseObjectWrapper parseObject = 
            new ParseObjectWrapper(tablename, objectId);
        
        //Read the valuefiled list from parcel
        List<ValueField> fieldList = new ArrayList<ValueField>();
        int size = parcel.readInt();
        for(int i=0;i<size;i++)
        {
            ValueField vf = (ValueField)parcel.readParcelable(ValueField.class.getClassLoader());
            fieldList.add(vf);
        }
        //add the field values
        FieldTransporter ft = 
            new FieldTransporter(
                    parseObject.po, parcel, IFieldTransport.DIRECTION_BACKWARD);
        for(ValueField vf: fieldList)
        {
            ft.transfer(vf);
        }
        //read essentials
        ParseObjectEssentials poe =
            (ParseObjectEssentials)parcel.readParcelable(ParseObjectEssentials.class.getClassLoader());
        
        parseObject.setParseObjectEssentials(poe);
        return parseObject;
    }
    
    //have the children override this
    public List<ValueField> getFieldList()
    {
        return new ArrayList<ValueField>();
    }

    //To represent createdby and lastupdatedby user objects
    //when parceled. I don't recreate them as ParseObjects but save their
    //essential attributes in separate objects.
    private ParseObjectEssentials poe;
    public void setParseObjectEssentials(ParseObjectEssentials inpoe)   {
        poe = inpoe;
    }
    public ParseObjectEssentials getEssentials()
    {
        if (poe != null) return poe;
        
        Date cat = po.getCreatedAt();
        Date luat = po.getUpdatedAt();
        ParseUser cby = getCreatedBy();
        ParseUser luby = getLastUpdatedBy();
        return new ParseObjectEssentials(
                cat, User.fromParseUser(cby),
                luat, User.fromParseUser(luby));
    }
    public boolean isParcelled()
    {
        if (poe != null) return true;
        return false;
    }
    
    //Utility methods that take into account if this 
    //object is parceled or not
    public User getCreatedByUser()    {
        if (!isParcelled())
        {
            //it is not parcelled so it is original
            return User.fromParseUser(getCreatedBy());
        }
        //it is parcelled
        return poe.createdBy;
    }
    public Date getCreatedAt()    {
        if (!isParcelled())
        {
            //it is not parcelled so it is original
            return po.getCreatedAt();
        }
        //it is parcelled
        return poe.createdAt;
    }
}//eof-class

You have seen the basics of this class in the previous article. The same class is taken and extended now to implement the parcelable methods required to send a ParseObjectWrapper through a Parcel.

As indicated a minute earlier the describe contents of this class returns 0 and this class also ignores the write time parcelable flags.

Most of the code in this class comes from the desire to do the following


public class Word extends ParseObjectWrapper {}
public class WordMeaning extends ParseObjectWrapper {}

//On the sending side
Word wordObject;
Intent i;
i.putExtra(Word.t_tablename, wordObject);
startActivity(i,...);

//In the receiving activity
Intent i = getIntent();
Word parceledWordObject = (Word)i.getExtra(Word.t_tablename);
//Use the parceledWordObject

Now, the solution provided by the parcelable ParseObjectWrapper code above is not as exact and precise and pure but pretty close as you will see. This highlevel understanding is key to quicly grasp the code that we presented for the ParseObjectWrapper.

Implementing writeToParcel()

The key methods to start exploring this code is the writeToParcel() method and the static counterpart method createFromParcel(). We will start the discussion with writeToParcel(). In this method we will write the following elements to the parcel in that order


tablename, objectId, fieldlist, field values, essentials

The tablename and the parse object id are required to recreate the ParseObject on the other side. As we have indicated there is no way to clone or serialize a ParseObject. So we will end up creating a new ParseObject using merely the tablename and its parseobject id.

we will then put in the parcel each of the attributes held by a parse object. To transport these field values from the parse object to the parcel we need some help on two accounts.

The phiolosophy of our parcelable implementation is such that we don't need our derived classes like Word and WordMeaning to implement the Parceleble and stream their own fields. We want the base class ParseObjecctWrappper to do this job for us. This keeps burden on the derived class to a minimum. So to alow the base class to parcel the attributes we want the derived classes to declare their fields using a mehtod called getFieldList(). This method returns a list of field names and their types. We can then store these field names and types in the parcel and retrieve them back on the other side to set them on the target newly created parse object. These field definitions are encapsulated in a class called ValueField with two attributes: a field name and its type. Here is the code for the ValueField.


public class ValueField
implements Parcelable
{
    public static String FT_int = "Integer";
    public static String FT_string = "String";
    public static String FT_Object = "Object";
    public static String FT_unknown = "Unknown";
    
    //Add more field types later
    public String name;
    public String type;
    
    public ValueField(String inName, String inFieldType)
    {
        name = inName;
        type = inFieldType;
    }
    public static final Parcelable.Creator<ValueField> CREATOR
        = new Parcelable.Creator<ValueField>() {
            public ValueField createFromParcel(Parcel in) {
                return new ValueField(in);
            }
            
            public ValueField[] newArray(int size) {
                return new ValueField[size];
            }
    }; //end of creator

    //
    @Override
    public int describeContents() {
        return 0;
    }
    
    public ValueField(Parcel in)
    {
        name = in.readString();
        type = in.readString();
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) 
    {
        dest.writeString(name);
        dest.writeString(type);
    }
    public String toString()
    {
        return name + "/" + type;
    }
    
    public static ValueField getStringField(String fieldName)
    {
        return new ValueField(fieldName, ValueField.FT_string);
    }
}//eof-class

Because a ValueField needs to be stored in the parcel I have made the ValueField to be a Parcelable by implementing the respective methods of a the Parcelable. This ValueField class also defines constants for the required field types. For now I have defined only a couple of types. You can extend this by adding other allowed primitive types.

So refering back to the writeParcel() method of the ParseObjectWrapper you realize that it is pretty simple to write the field names and their type names to the parcel.

Field Transporters

The next task is to write the values of each attribute or field of the ParseObject into the parcel. Both Parcel and the ParseObject provide typed methods to get and set the values. So we need a match maker to take the value from one to the other. To do this I have an interface and a couple of classes to do this translation


//Transfer value from one source to another
public interface IFieldTransport 
{
    public static int DIRECTION_FORWARD = 1;
    public static int DIRECTION_BACKWARD= 2;
    
    //Transfer from one mode to another
    public void transfer(ValueField f);
}

//A class to transport an integer between a 
//ParseObject and a Parcel
//ParseObject is source and Parcel is target
//Direction indicates how this value should be transported
public class IntegerFieldTransport 
implements IFieldTransport
{
    ParseObject po;
    Parcel p;
    int d = IFieldTransport.DIRECTION_FORWARD;
    
    public IntegerFieldTransport(ParseObject inpo, Parcel inp){
        this(inpo,inp,DIRECTION_FORWARD);
    }
    public IntegerFieldTransport(ParseObject inpo, Parcel inp, int direction)
    {
        po = inpo;
        p = inp;
        d = direction;
    }
    @Override
    public void transfer(ValueField f) 
    {
        //1
        if (d == DIRECTION_BACKWARD) {
            //parcel to parseobject
            int i = p.readInt();
            po.put(f.name, i);
        }
        else {
            //forward
            //parseobject to parcel
            int i = po.getInt(f.name);
            p.writeInt(i);
        }
    }
}

public class StringFieldTransport 
implements IFieldTransport
{
    ParseObject po;
    Parcel p;
    int d = IFieldTransport.DIRECTION_FORWARD;
    
    public StringFieldTransport(ParseObject inpo, Parcel inp){
        this(inpo,inp,DIRECTION_FORWARD);
    }
    
    public StringFieldTransport(ParseObject inpo, Parcel inp, int direction)
    {
        po = inpo;
        p = inp;
        d = direction;
    }
    @Override
    public void transfer(ValueField f) {
        if (d == DIRECTION_BACKWARD)
        {
            //parcel to parseobject
            String s = p.readString();
            po.put(f.name, s);
        }
        else
        {
            //forward
            //parseobject to parcel
            String s = po.getString(f.name);
            p.writeString(s);
        }
    }
}

Given this interface and the type translators I can gather them in a registry and have the registry handle transfer for all types. Here is the code for a FieldTransporter that knows how to transfer all field types that are known to it.


public class FieldTransporter 
implements IFieldTransport
{
    ParseObject po;
    Parcel p;
    int d = IFieldTransport.DIRECTION_FORWARD;
    
    Map<String,IFieldTransport> transporterMap;
    
    public FieldTransporter(ParseObject inpo, Parcel inp, int direction){
        po = inpo;
        p = inp;
        d = direction;
        
        //Register the all the translators/tranporters
        register();
    }
    private void register()
    {
        transporterMap = new HashMap<String,IFieldTransport>();
        //register integers
        transporterMap.put(
                ValueField.FT_int, 
                new IntegerFieldTransport(po,p,d));
                
        //register string transporter
        transporterMap.put(
                ValueField.FT_string, 
                new StringFieldTransport(po,p,d));
                
        //Other missing transporters                
    }
    private IFieldTransport getTransportFor(String fieldType)
    {
        IFieldTransport ift = transporterMap.get(fieldType);
        if (ift == null)
        {
            throw new RuntimeException("Problem with locating the type");
        }
        return ift;
    }
    
    @Override
    public void transfer(ValueField f) 
    {
        IFieldTransport ift = getTransportFor(f.type);
        ift.transfer(f);
    }
}//eof-class

Given this FieldTransporter it is now easy to see how the writeParcel() method does its magic of writing the values for all the fields from the parseobject to the parcel. That code is repeated here for quick look


//add the field values
FieldTransporter ft = 
    new FieldTransporter(
            parseObject.po, parcel, IFieldTransport.DIRECTION_BACKWARD);
for(ValueField vf: fieldList)
{
    ft.transfer(vf);
}

See how the field transported is instantiated with source, target and direction and then for each valuefield given by the parseobjectwrapper the field values are transfered. This approach keeps the type safety of the writes between the ParseObject and the parcel. Keep in mind that as you are likely to have more field types you will need to create transporters for those and add them to the FieldTransporter registration above.

What is ParseObjectEssentials?

So far we have gathered the primitive attributes of the source parseobject and transfered over. However the source parse object has some attributes that point to other parse objects. Especially the two user objects: the one who created the parse object and the one that last updated it.

Potentially you can extend the parcelables concept to these child objects as well. Due to time constraints I have taken a simpler approach for now. In this approach I will strip out the essentials of these two user objects and encapsulate them into a home grown User object as laid out in the begining of the article and capture both the users in a consolidated object called ParseObjectEssentials. Once I have this ParseObjectEssentials extracted from the current ParseObject that is being parceled, I can instead parcel the ParseObjectEssentials in place of the child ParseObjects. So here is the definition for the ParseObjectEssentials


public class ParseObjectEssentials
implements Parcelable
{
    //Add more fields if desired from their respective ParseObjects
    public Date createdAt;
    public User createdBy;
    public Date lastUpdatedAt;
    public User lastUpdatedBy;
    
    public ParseObjectEssentials(Date createdAt, User createdBy,
            Date lastUpdatedAt, User lastUpdatedBy) {
        super();
        this.createdAt = createdAt;
        this.createdBy = createdBy;
        this.lastUpdatedAt = lastUpdatedAt;
        this.lastUpdatedBy = lastUpdatedBy;
    }
    public static final Parcelable.Creator<ParseObjectEssentials> CREATOR
        = new Parcelable.Creator<ParseObjectEssentials>() {
            public ParseObjectEssentials createFromParcel(Parcel in) {
                return new ParseObjectEssentials(in);
            }
            
            public ParseObjectEssentials[] newArray(int size) {
                return new ParseObjectEssentials[size];
            }
    }; //end of creator

    @Override
    public int describeContents() {
        return 0;
    }
    
    public ParseObjectEssentials(Parcel in)
    {
        createdAt = new Date(in.readLong());
        createdBy = (User)in.readParcelable(User.class.getClassLoader());
        lastUpdatedAt = new Date(in.readLong());
        lastUpdatedBy = (User)in.readParcelable(User.class.getClassLoader());
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) 
    {
        dest.writeLong(this.createdAt.getTime());
        dest.writeParcelable(createdBy, flags);
        dest.writeLong(lastUpdatedAt.getTime());
        dest.writeParcelable(lastUpdatedBy, flags);
    }
    public static ParseObjectEssentials getDefault()
    {
        Date cat = new Date(0);
        User auser = User.getAnnonymousUser();
        Date luat = new Date(0);
        return new ParseObjectEssentials(cat,auser,luat,auser);
    }
}//eof-class

So to finish the writeToParcel() of the ParseObjectWrapper I am saving one of these ParseObjectEssentials in the parcel. See the ParseObjectWrapper code how I obtain this ParseObjectEssentials from the core embedded ParseObject of the ParseObjectWrapper.

The Otherside: Re Creating the ParseObjectWrapper

As a parcelable the ParseObjectWrapper needs to recreate the object from the parcel. See the static create() function that returns the ParseObjectWrapper from a given parcel. In this function we read things in reverse.

I first read the table name and the object id belonging to the old parse object that was parceled. From these two arguments I create a Parse shell object. I then read the field definitions to see how many attributes are available and parceled for this parse object. Then I use the field transporters to transfer each field and its value to the newly creaed ParseObject. I then take this ParseObject and create a new ParseObjectWrapper. At this point I have the ParseObjectWrapper that is ready to be returned. However I also need to read the ParseObjectEssentials at this point and set it on the ParseObjectWrapper.

Now the ParseObjectWrapper becomes quite context sensitive. It sits in possibly multiple states.

When it is originally created it is just holding to a ParseObject that is created with merely its tablename and even with out an ID as the ParseObject is not even saved in the parse cloud.

As a next state the ParseObjectWrapper could be holding a ParseObject that is fully saved in the parse cloud.

Then the parseobjectwrapper could have been parcelled and recreated on the otherside. In this state the parseobject it holds is merely a standin and not tied to the server. In this state the parseobjectwrapper also holds a ParseObjectEssentials. So it is possible to ask the ParseObjectWrapper if it is parcelled.

I have created some methods such as the last created user and last updated by so that they take into account in which state the ParseObjectWrapper is and accordingly return the right values.

Parceling the Word

Let us see now how we package a word into a parcel and bring it back. Here is the definition for the Word based on our new ParseObjectWrapper


public class Word 
extends ParseObjectWrapper
{
    public static String t_tablename = "WordObject";
    public static String PARCELABLE_WORD_ID = "WordObjectId";
    
    //Only two fileds
    public static String f_word = "word";
    public static String f_meaning = "meaning";
    
    //Constructors: A new word from scratch
    public Word(String word, String meaning){
        super(t_tablename);
        setWord(word);
        setMeaning(meaning);
    }
    //Wrapping from a ParseObject gotten from the cloud
    public Word(ParseObject po)    {
        super(po);
    }
    //Recreated using a previously Parceled word
    public Word(ParseObjectWrapper inPow)    {
        super(inPow);
    }
    
    //Accessors
    public String getWord()    {
        return po.getString(f_word);
    }
    public void setWord(String in)    {
        po.put(f_word,in);
    }
    public String getMeaning()    {
        return po.getString(f_meaning);
    }
    public void setMeaning(String in)    {
        po.put(f_meaning,in);
    }
    public String toString()
    {
        String word = getWord();
        String user = getCreatedBy().getUsername();
        return word + "/" + user;
    }
    //have the children override this
    @Override
    public List<ValueField> getFieldList()
    {
        ArrayList<ValueField> fields = new ArrayList<ValueField>();
        fields.add(ValueField.getStringField(Word.f_word));
        fields.add(ValueField.getStringField(Word.f_meaning));
        return fields;
    }
}//eof-class

If you see the previous article you know that this version of Word is very very close. Main addition is that the Word class now provides its field list by overriding getFieldList(). It also has an additional constructor that accepts the ParseObjectWrapper as an input. This constructor is useful in recreating the word once it is passed through the Parcelable.

We are now ready to implement the WordMeanings activity that we introduced in the begining of this article.

Implementing Word Meanings List Activity

Now as I broach the subject of implementing the WordMeaningsListActivity I will document the following

1. How to invoke this activity by passing a Word through an intent

2. How to retrieve that word from the intent

3. How can I access the word so that I can change the title of the activity based on the word whose meanings we seek

4. How do I use the word to query for its word meanings

Passing Word as an Intent Extra

if you notice the word list activity picture (shown in the begining of the article) you see that each row represents a Word object defined by the Word class above. If you tap the Meanings button it will need to invoke the WordMeaningsListActivity which is also shown at the begining. Here is how that activity transfer happens through an intent extra


private void respondToClick(WordListActivity activity, Word wordRef)
{
    Intent i = new Intent(activity,WordMeaningsListActivity.class);
    i.putExtra(Word.t_tablename,wordRef);
    activity.startActivity(i);
}    

Recreating the Word from the intent extra

Notice how the word object is passed to the intent extra as a parcelable. Let's see how get our Word object back on the other side. Here is the code snippet from WordMeaningsListActivity obtaining the Word object back


private Word getParceledWordFromIntent()
{
    Intent i = this.getIntent();
    ParseObjectWrapper pow = 
        (ParseObjectWrapper)i.getParcelableExtra(Word.t_tablename);
    Word parceledWord = new Word(pow);
    return parceledWord;
}

Notice how I retrieve a ParseObjectWrapper first from the intent extra and then use that to wrap it in a Word object.

Using the Retrieved Word object to set the context for the activity

Now I can use the Word object to access all its attributes and use its method. Here is how for example I can set the title of the activity


Word parceledWord;
activity.setTitle(parceledWord.getWord());

See that I am able to transfer the word through the intent and use it without resorting to the underlying parse object.

Had I not been able to pass the word via the intent, I would have had to pass just the parse object ID of the word instead and do a query again to the parse backend to retrieve the word object to get its word string value and who created it and when etc. It is to avoid this second query to the server I went to this trouble of writing this much of parceling code.

Using the Retrieved Word to search for its meanings

Let's see how I can use this parceled Word object to retrieve WordMeanings. First let me show you how a Word and a WordMeaning are connected


public class WordMeaning extends ParseObjectWrapper
{
    //Design the table first
    public static String t_tablename = "WordMeaningObject";
    public static String f_word = "word";
    public static String f_meaning = "meaning";
    
    public WordMeaning(String wordMeaning, Word inParentWord)
    {
        super(t_tablename);
        setMeaning(wordMeaning);
        setWord(inParentWord);
    }

    //Make sure there is a way to construct with a straight 
    //Parse object
    public WordMeaning(ParseObject po)
    {
        //Create a check in the future if it is not of the same type
        super(po);
    }
    public void setMeaning(String meaning)   {
        po.put(f_meaning, meaning);
    }
    public void setWord(Word word)   {
        po.put(f_word, word.po);
    }
    public String getMeaning()   {
        return po.getString(f_meaning);
    }
    public Word getWord()   {
        return new Word(po.getParseObject(f_word));
    }
}

See that a WordMeaning carries an attribute pointing to its parent word. We will use this property to query all the word meanings for a given word.


private void populateWordMeaningsList(Word word)
{
    ParseQuery query = new ParseQuery(WordMeaning.t_tablename);
    query.whereEqualTo(WordMeaning.f_word, word.po);
    query.orderByDescending(WordMeaning.f_createdAt);
    
    //Include who created me
    query.include(WordMeaning.f_createdBy);
    
    //Include who the parent word is
    query.include(WordMeaning.f_word);
    
    //How can I include the owner of the word
    query.include(WordMeaning.f_word + "." + Word.f_createdBy);
    
    this.turnOnProgressDialog("Going to get word meanings for:" + word.getWord(), 
            "Patience. Be Right back");
    query.findInBackground(new FindCallback() {
      public void done(List<ParseObject> objects, ParseException e) {
        turnOffProgressDialog();
        if (e == null) {
            // The query was successful.
            successfulQuery(objects);
        } else {
            // Something went wrong.
            queryFailure(e);
        }
      }
    });        
}
private void successfulQuery(List<ParseObject> objects)
{
    this.setEmptyViewToNoRows();
    ArrayList<WordMeaning> wordMeaningList = new ArrayList<WordMeaning>();
    for(ParseObject po: objects)
    {
        WordMeaning wordMeaning = new WordMeaning(po);
        wordMeaningList.add(wordMeaning);
    }
    
   WordMeaningListAdapter listItemAdapter = 
       new WordMeaningListAdapter(this
               ,wordMeaningList
               ,this);
   this.setListAdapter(listItemAdapter);
}
private void queryFailure(ParseException x)
{
    this.setErrorView(x.getMessage());
}

This code is very similar to the code in the previous article where we queried for words. The nuance here is how we specify the where clause that involve a parent word parse object. Here is that line from the code above


query.whereEqualTo(WordMeaning.f_word, word.po);

Notice that I am able to use the parceled word object as we would use it in any other occasion. The rest of the code is very similar to the previous article.

Creating the Meaning for a Word

Let me turn the attention to the create word button which invokes the Create word activity. Here also I can benefit from the parceled word directly. Here is how I transport the the already parceled word one more time through the intent to the create word activity


public void createWordMeaning(View v)
{
    Intent i = new Intent(this,CreateAMeaningActivity.class);
    i.putExtra(Word.t_tablename,parceledWord);
    startActivity(i);        
}

Notice how the parceled word is parceled again through the extra. This means that the ParseObjectWrapper needs to be aware of its state and parcel successfully both when it had never been parceled before and also when it is already parceled. You can see this in the writeToparcel() method and also the creating the parseobjectwrapper from the parcel in the create() method of the ParseObjectWrapper.

Here is how I retrieve the parceled word for the CreateWordMeaning activity


private Word getParceledWordFromIntent()
{
    Intent i = this.getIntent();
    ParseObjectWrapper pow = 
        (ParseObjectWrapper)i.getParcelableExtra(Word.t_tablename);
    Word parceledWord = new Word(pow);
    return parceledWord;
}

Notice how identical is this code to the one we used to retrieve the parceled word the first time.

See now how I use the retrieved word to populate the word detail necessary to display in the CreateWordMeaning activity


private String getWordDetail(Word pword)
{
    String by = pword.getCreatedByUser().username;
    Date d = pword.getCreatedAt();
    
    DateFormat df = SimpleDateFormat.getDateInstance(DateFormat.SHORT);
    String datestring =  df.format(d);
    
    return by + "/" + datestring;
}

Finally here is how I use the passed in Word to create a WordMeaning in the parse cloud


public void createMeaning(View v)
{
    if (validateForm() == false)   {
        return;
    }
    //get meaning from the text box
    String meaning = getUserEnteredMeaning();
    
    WordMeaning wm = new WordMeaning(meaning, parceledWord);
    turnOnProgressDialog("Saving Word Meaning", "We will be right back");
    wm.po.saveInBackground(new SaveCallback() {
        @Override
        public void done(ParseException e) {
            turnOffProgressDialog();
            if (e == null)    {
                wordMeaningSavedSuccessfully();
            }
            else {
                wordMeaningSaveFailed(e);
            }
        }
    });
}
private void wordMeaningSaveFailed(ParseException e) {
    String error = e.getMessage();
    alert("Saving word failed", error);
}
private void wordMeaningSavedSuccessfully(){
    alert("word meaning saved", "Success");
}

Notice in this code that I have used the twice parceled word as the direct target for the parent word attribute of the word meaning I am saving.

Summary

This concludes our discussion on the critical topic of how to use parcelables to effectively develop with Parse. I have presented the detail architecture of how parcelables work in Android. I have reasoned why parcelables are VERY important when coding with Android and Parse. I have presented ideas and a quick workable framework. As I have clearly stated the intention of the framework you can tweak this framework or create a brand new one to meet the stated guidelines. Hopefuly if time permits I have another installement on parse that talks aboout Push notifications.

Key Questions

1. Why are parcelables important while working with Parse?

2. How do you implement a Parcelable?

3. what is Parcelable.describeContents()?

4. what are Parcelable flags?

5. what is the creator static method in a parcelable?

6. Are ParseObjects parcelable?

7. Are ParseObjects serializable?

8. Can ParseObjects be converted to JSON strings?

9. How can I query for parse objects where an attribute points to another parse object?

References

1. My notes on understanding parcelables

2. Android API docs on Parcel

3. The previous article on basic parse