Some of your mobile applications may require the ability to store data on a server. This data may be as simple as the user profiles of the users that are using your mobile application. You may want to store user scores if your mobile application is a game. Or your application is a collaborative application where one user needs to see data created by another user. Or you may want to provide your mobile application a cross-device synching.
These types of collaborative data needs are accomodated by having a server available to your mobile application as a service. This server side technology space, especially for mobile needs, now has a name. It is called BAAS: Backend As A Service. There are a large number of companies now in this BAAS space. Typical features offered by a BAAS platform are
In this and the next few articles I will cover some of these features by taking one of the popular BAAS companies Parse.com as an example. Other emerging players in the BAAS space are
ACS - Appcelerator Cloud Services (Previously Cocoafish)
Applicasa
Stackmob
Microsoft Azure Mobile Services
Kinvey
Fatfractal
We will explore the Parse cloud API by writing a simple Android application that goes through the basic features of Parse. That should give you enough information about the Parse API to get started.
The sample application I am going to create is a multi user application. Each user is able to create a word and also see the words created by other users. In addition to working with these words, being a multi user application this app needs to have the basic user management features such as signup, login, reset password, and logout.
Lets start with the home screen that the user will be presented when the application is downloadd and installed.
when you see the application for the first time, you have the option of either sign up or login if you have already signed up.
Note: Parse also allows logins from other websites such as Facebook and Twitter. However I am not covering the Facebook or Twitter integration here. I will leave that as something you could research and implement from the excellent documentation available on the Parse site.
Lets plan the sign up page first. This sign up page could look something like this
As you can see I am collecting the essentail sign up information from the form and I would call the parse API to register the user with these details.
Once the sign up is complete, you can use the following page to login (However, note that when the user signe up is successful the user is automatically logged in!. You will need to logout to make use of this login screen, perhaps subsequently)
Again nothing surprising with this login screen. I am collecting the userid and password so that I can call the parse api to login. As there is likely to be delay when contacting parse on the server for login, it is better to put a wait dialog. This interaction is shown below
Most Parse APIS come with their asynchronous variants. These APIs provide a callback when the call returns so that I can programmatically turn off the progress dialog.
It is possible that a user may not have remembered the password that was used. Using parse it is quite easy to implement the Reset Password ability. The screen for the reset password facility could look like the following
All I need as an input to reset the password is the email. The form above would collect the email and once you click the reset password button the parse API to reset the password could be called by passing the email. Parse would subsequently send a link to the email specified. User can visit this link to give a new password.
Once you are logged in, the screen I would present for this application is a welcome screen that looks like this
Using this screen I will demonstrate three things. The first is to show the list of users that have registered so far. This will explore the parse apis available to query for users.
We will then explore how to create a data object and store it in the parse cloud. To do this I will create a "word" object and store it in the parse cloud. Using the "Create Word" button shown in the activity above I will create many words and then use the "Show Word List" button to see all the words that are created so far.
Here is the screen that shows the list of registered users.
In this screen there is only one user because I am the only one that is registered so far. If there were more it will show all of them. Of course it is possible to page through users as well if there are too many. However for this article I am not going to show paging and you need to refer to the parse documentation on how to do that.
Here is the screen that allows us to create a word and store it in the parse cloud
Once I collect the word and its meaning I can call the parse API to store it in the parse cloud. A goal of this application is to develop a very simple minded community based dictionary where meanings are provided by other users.
Once a user creates a word, the user can browse for all of the existing words. here is the screen that displays the available set of words
This screen lists the words and which user has created each word and when. This screen also provides the ability to delete a word. The meanings button allows multiple users to provide meanings for a word. In this article I won't go into the additional screens which are used to create and browse meanings. Those concepts are very similar to creating words and browsing words, as both words and meanings are parse objects.
This completes the quick over view of the application I am planning to implement with Parse. I will now go into setting up parse.
The sample application I have described so far is a good candidate to develop with the parse api. I will implement all of the features indicated in the use case using the parse api. That will give an excellent introduciton to parse and its API.
Before I implement the sample application let us first cover how to setup parse and get started with it.
Starting with parse.com is very simple. Visit parse.com and create an account. With in that account create an application. Once you create an application you will be the owner of that application. You can create as many applications as you would like.
Note: The links needed to create the account and create the application may change on the Parse.com site. You should be able to navigate and do those basic tasks.
Once an application is created Parse creates a set of keys that you need to initialize your mobile application with. Parse provides a dashboard for your application to easily copy and paste these keys. Here is that dashboard for the first sample app I have created below
I have truncated the keys in this picture for security purposes. From this panel you will be able to copy and paste these keys into your mobile application. I will show you very shortly how to use these keys so that your application is allowed to communicate with parse in the cloud.
But first you should download the necessary jar files and create the android mobile application. To bootstrap the application development with parse, Parse has provided a sample android application called "Parse Starter" that you can download and use as a starting point. You can download this sample template application from the following URL
https://www.parse.com/apps/quickstart
Once you are here choose your platform and download and setup the parse starter application in your eclipse ADT. Depending on the release of parse download, what I cover in this chapter may be slightly different than what you download. But the general prinicples and directions should apply.
Once you download and setup the parse starter application in your prefered IDE it will most likely fail with errors in a file called ParseApplication.java. This is because Parse has intentionally left the place holders for putting the keys that I have shown earlier. Once you place those keys this file will look like the following
public class ParseApplication extends Application {
private static String tag = "ParseApplication";
private static String PARSE_APPLICATION_ID
= "vykek4ps.....";
private static String PARSE_CLIENT_KEY
= "w52SGUXv....";
@Override
public void onCreate() {
super.onCreate();
Log.d(tag,"initializing with keys");
// Add your initialization code here
Parse.initialize(this, PARSE_APPLICATION_ID, PARSE_CLIENT_KEY);
// This allows read access to all objects
ParseACL defaultACL = new ParseACL();
defaultACL.setPublicReadAccess(true);
ParseACL.setDefaultACL(defaultACL, true);
Log.d(tag,"initializing app complete");
}
}
After plugging in the application ID and the client key in the code above the parse starter application is ready for us to work with Parse on the server. The "ACL" in the code above stands for access control lists. For this write up I set this to the default read access for all objects created by users. Outside of that this writeup doesn't cover the security aspects of Parse and the reader is advised to read the Parse documentation.
We are almost ready to start implementing the application we have described. Before that let me talk about few basic concepts of Parse first.
In parse objects are stored as a set of key value pairs. Objects don't have to stick to a predefined schema like columns in a relational table or attributes in a class definition. Once you have a parse object you can add as many columns as you want. They all get stored in that object.
An object has a type name associated with it. It is like a tablename in a realtional database. However, many objects that belong to this type or table name can have a varied set of columns and respective values. This is a contrast to types in typed languages and tables in relational databases.
Each object in parse is guranteed to have an object id, when that object is created and when that object is last updated. You can place most types of objects as values for a particular key. These objects are typically converted to some stream representation and stored. When they are retrieved they are retrieved as their original type of object. So, a parse object can store other parse objects as the target value for a given key. This means a parse object can have relationships with other objects, especially the parents.
If you application has say 30 types of java objects. When stored in parse they are all represented as typeless key-value-pair based parse objects. It is up to you to map them to your respective java objects for type safety when needed.
A ParseUser is also a ParseObject and provides some additional typed features such as user name, email etc without reverting to the underlying key names. A ParseUser also provides methods necessary to login, logout etc.
Because a parseuser is a parseobject you can put additional attributes in to a user object if you want.
Unlike a relational databases there is no SQL for querying parse objects. There is a java API provided that you can use to retrieve parse objects.
Using parse query api you can retrieve only one type of object at a time. This means you cannot selectively join multiple parse object types and retrieve both of them.
However some type of joins can be accomplished through other means. For example if I have a word and if that word has many meanings then I will represent the word and word meaning as two types of objects. Then the word meaning will have a relationship to its word as an additional attribute. Now I can say get all the word meanings whose word is so and so.
When you retrieve a primary object you can tell the query to include the associated objects if needed.
You can also tell the query some caching policies to save on latency. You can do this both while saving the object or while retriving the objects through queries.
These basics should be sufficient to get started writing the application that I have suggested and pick up the nuances as I show you how I have implemented the application in the next section.
In this part of the arcticle I am going to take each screen that was presented earlier and show you the key code snippets that demonstrate how the parse API is used to accomplish that use case. If you are interested in the entire application source code, you can download it from the project download URL that is given in the references at the end of this article.
Lets start with the begining screen, the signup screen. If you notice the sign up screen that was presented earlier you will see that I am gathering the username, password and email. Using these values the code below demonstrates how I use parse to sign up the user.
private void signup(String userid, String email, String password)
{
ParseUser user = new ParseUser();
user.setUsername(userid);
user.setPassword(password);
user.setEmail(email);
//Show the progress dialog
turnOnProgressDialog("Signup", "Please wait while I sign you up");
//Go for signup with a callback
user.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
turnOffProgressDialog();
if (e == null) {
// Hooray! Let them use the app now.
signupSuccessful();
} else {
// Sign up didn't succeed. Look at the ParseException
// to figure out what went wrong
signupFailed(e);
}
}
});
return;
}//signup-method
private void signupSuccessful()
{
//Go to signup successful page
//finish
gotoActivity(SignupSuccessActivity.class);
finish();
}
private void signupFailed(ParseException x)
{
//stay on the page
//Put an error message for the exception
String message = x.getMessage();
alert("Signup", "Failed:" + message);
}
Note that as this code is taken from the middle of a larger code base. So use it to primarily understand how the parse apis are used. Don't try to compile as it won't as it refers to some methods that are not defined here. However the intention of those methods should be obvious. For example the "alert()" method is there to put an alert dialog. The gotoActivity() method is there to transfer control to another activity. the turnOnProgressDialog() method is there to show the progress dialog until the parse method returns through its callback.
Now to the main flow of this code. I first create a new parse object called ParseUser and fill it up with user related information that I have collected through the user registration form. I then call the progress dialog in anticipation of the call to the parse api signUpInBackground(). This sign up API is fundamentally asynchronous. This method takes a callback object that provides a done() callback method. In the "done()" method I first turn off the progress dialog. I then figure out if it is a success or a failure. if signup is successful parse automatically logs in the user on the device.
With this the user is signed up. Now the user can do things like login, logout etc.
To know if the user is logged in or not you can use the following code snippet
private void setViewsProperly()
{
ParseUser pu = ParseUser.getCurrentUser();
if (pu == null)
{
//User is not logged in
showLoggedOutView();
return;
}
//User is logged in
showLoggedInView();
}
It is quite simple. I called the static method on the ParseUser class called getCurrentUser(). If this method returns a valid user then the user is loggedin. If not the user is not logged in.
You can use the following code snippet to logout a user from the current session
private void logoutFromParse()
{
ParseUser.logOut();
}
Once you call this logout method the ParseUser.getCurrentUser() will return a null indicating that no user is in the current session.
To understand login, turn your attention to the login activity presented in the begining of the article. Here I am collecting the userid and password. Once I have these fields the code to login is straight forward and provided right below
public void login(View v)
{
if (validateForm() == false){
return;
}
//form is valid
String sUserid = getUserid();
String sPassword = getPassword();
turnOnProgressDialog("Login","Wait while I log you in");
ParseUser.logInInBackground(sUserid, sPassword, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
turnOffProgressDialog();
if (user != null) {
reportSuccessfulLogin();
} else {
reportParseException(e);
}
}
});
}//eof-login
private void reportParseException(ParseException e)
{
String error = e.getMessage();
reportTransient("Login failed with:" + error);
}
private void reportSuccessfulLogin()
{
gotoActivity(ParseStarterProjectActivity.class);
finish();
}
Again the login call is available on the ParseUser object as a static method. I am also using this method in the background by providing a callback as is the usual pattern for android for talking to server side content. This pattern is very similar to the pattern of using the sign up api and almost every other parse API as they all have the callbacks so that they don't stop the main thread.
What if one forgets the password. of course provide a way to reset it. See the reset activity presented in the begining. I use this activity to collect the email of the account and call the requestPasswordResetInBackground() static method on the ParseUser class. The code is given below.
public void resetPassword(View v)
{
if (validateForm() == false){
return;
}
String sEmail = email.getText().toString();
turnOnProgressDialog("Reset Password","Wait while I send you email with password reset");
//userid is there
ParseUser.requestPasswordResetInBackground(sEmail,
new RequestPasswordResetCallback() {
public void done(ParseException e) {
turnOffProgressDialog();
if (e == null) {
reportSuccessfulReset();
} else {
reportResetError(e);
}
}
});
}//eof-reset
private void reportSuccessfulReset(){
gotoActivity(PasswordResetSuccessActivity.class);
finish();
}
private void reportResetError(ParseException e)
{
//stay on the page
//Put an error message for the exception
String message = e.getMessage();
alert("Reset Password", "Failed:" + message);
}
The pattern is identical. Call the method. provide a callback and deal with success and failure. If successful Parse will send an email with a URL to reset the password.
Here is the code you can use to see who are the users that have registered so far (Refer to the list of users activity presented in the begining of the article)
private void populateUserNameList()
{
ParseQuery query = ParseUser.getQuery();
this.turnOnProgressDialog("Going to get users", "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)
{
ArrayList<ParseUserWrapper> userList = new ArrayList<ParseUserWrapper>();
for(ParseObject po: objects)
{
ParseUser pu = (ParseUser)po;
ParseUserWrapper puw = new ParseUserWrapper(pu);
userList.add(puw);
}
ArrayAdapter<ParseUserWrapper> listItemAdapter =
new ArrayAdapter<ParseUserWrapper>(this
,android.R.layout.simple_list_item_1
,userList);
this.setListAdapter(listItemAdapter);
}
private void queryFailure(ParseException x)
{
this.setErrorView(x.getMessage());
}
We first use the ParseUser object to get a ParseQuery object. Then use a find method on that query object. Once this method returns through a callback we retrieve the collection of parseuser objects and populate a list adapter that can be used to populate list shown in the list of users activity. I will revisit the query object again when I talk about querying for the word objects.
So far I have shown you how to set up the stage to start the actual app development. You know now how to signup, login, logout, and reset password when needed. The next two things I am going to show here are how to create objects in parse and how to query for them.
lets start with creating an object and storing it in the parse cloud. For this if you were to recall the screens presented in the begining I would be creating a word. In that create word activity I will collect a word and its meaning and try to store it in parse. To do this in basic parse all I have to do is given in the following psuedo code
ParseObject po = new ParseObject("word_table");
po.put("word", "prow");
po.put("word","I think it means something to do with boats and ships!");
po.saveInTheBackground(...withsomecallback-method...)
This is the level of API provided by parse. In Java you can see that I am using the ParseObject as primarily a type-less collection of key value pairs. It may be worthwhile to create a typed class called Word with two fields in it. Here is some psuedo code for it
public class Word extends ParseObjectWrapper
{
public Word(String word, String meaning);
public String getWord();
public String setWord(String word);
public String getMeaning();
public String setMeaning();
}
This type of definition for a word allows us to treat words as java objects and not merely as a collection of strings. The base class ParseObjectWrapper can hold the underlying parse object and store the field values in that parse object as the key value pairs.
Here is the actual code for the ParseObjectWrapper taken from the sample project
public class ParseObjectWrapper
{
public static String f_createdAt = "createdAt";
public static String f_createdBy = "createdBy";
public static String f_updatedAt = "updatedAt";
public static String f_updatedBy = "updatedBy";
public ParseObject po;
public ParseObjectWrapper(String tablename)
{
po = new ParseObject(tablename);
po.put(f_createdBy, ParseUser.getCurrentUser());
}
public ParseObjectWrapper(ParseObject in)
{
po = in;
}
//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);
}
}//eof-class
Here is how I have designed this parse object wrapper class as a first attempt. It will hold a reference to an actual ParseObject. There are two ways a parse object wrapper can acquire a ParseObject. When you are creating a parse object for the first time you can simply tell what the tablename for that parse object is. Or if you happen to have retrieved a parse object from the cloud and wants to alter it then you can pass in that parse object directly.
Another feature I have built into this parse object wrapper is this: the native ParseObject doesnt carry with it which user created it or last updated it. So the parse object wrapper provides field names for these two additional attributes starting with "f_...". These additional fields allow me to store these two types of users (created by, and last updated by) with every parse object. Given this parse object wrapper, here is how I can craft the Word class
public class Word
extends ParseObjectWrapper
{
//Name of the table or class for this type of object
public static String t_tablename = "WordObject";
//Only two fileds
public static String f_word = "word";
public static String f_meaning = "meaning";
public Word(String word, String meaning)
{
super(t_tablename);
setWord(word);
setMeaning(meaning);
}
public Word(ParseObject po)
{
super(po);
}
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;
}
}//eof-class
This is quite straight forward. I have used the convention of "t_" for tablenames and "f_" for field names. These static constants are as important as the methods that they are used in. This is because when you provide queries for this object you will be using these string names for the fields to query by.
With the right class definition for a Word I am now ready to create a Word and store it in the parse cloud.
public void createWord(View v){
if (validateForm() == false) {
return;
}
//form is valid
String sWord = getWord();
String sMeaning = getMeaning();
Word w = new Word(sWord, sMeaning);
turnOnProgressDialog("Saving Word", "We will be right back");
w.po.saveInBackground(new SaveCallback() {
@Override
public void done(ParseException e) {
turnOffProgressDialog();
if (e == null) {
//no exception
wordSavedSuccessfully();
}
else {
wordSaveFailed(e);
}
}
});
}//eof-login
private void wordSaveFailed(ParseException e)
{
String error = e.getMessage();
alert("Saving word failed", error);
}
private void wordSavedSuccessfully()
{
gotoActivity(WordListActivity.class);
//Don't finish it as back button is valid
//finish();
}
Notice how in this code I am able to create a Word object through its constructor and not worry about setting the field names explicitly on the parse object. Where needed this also ensures that you are not mistyping field names everytime they are needed. Because a parse object allows any field name, if you were to mistype, you will end up creating new attributes that you dont intend to! However there may be places that you legitimately want to do this. But at least for the most common cases this is a good firewall to have.
(sk)Also notice in that code that you are using the real parse object from the parse object wrapper (w.po) to fire off the parse apis such as save.
Note: Also the code presented here for the parse object wrapper and the word are stripped down to show you the minimum necessary for our current needs. If you were to look up the downloadable project you will see that these classes have slightly more code. The additional code was necessary when you start passing objects like "Word" through parcelables. That is a topic for another article. So keep that in mind when you see the original code in the downloaded project.
Lets turn our attention to how I will query for these word objects and paint them in a list through android list adapters.
The code below shows you how to query for objects of type Word.
private void populateWordList()
{
ParseQuery query = new ParseQuery(Word.t_tablename);
query.orderByDescending(Word.f_createdAt);
query.include(Word.f_createdBy);
query.setCachePolicy(ParseQuery.CachePolicy.CACHE_ELSE_NETWORK);
//Milliseconds
query.setMaxCacheAge(100000L);
this.turnOnProgressDialog("Going to get words", "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)
{
ArrayList<Word> wordList = new ArrayList<Word>();
for(ParseObject po: objects)
{
Word puw = new Word(po);
wordList.add(puw);
}
WordListAdapter listItemAdapter =
new WordListAdapter(this
,wordList
,this);
this.setListAdapter(listItemAdapter);
}
private void queryFailure(ParseException x)
{
this.setErrorView(x.getMessage());
}
As indicated before Parse uses called ParseQuery to perform queries. A parse query object is initialized with the type of object you are querying. I used the Word class to indicate what this type is. in our case the variable Word.t_tablename points to the name of the table. In parse this table name is refered as a "class" in line with object databases as opposed to relational databases.
we then set the order clause using the field name by which I am ordering. So I use the Word.f_createdBy as the field to order by. Notice again how the static field definitions on the Word and ParseObjectWrapper are used here to avoid typing the string names directly.
we then set the cache policy in milliseconds so that I don't go to the server too often. Then I call the findInBackground() method on the query object. Also see that when I am called back I take the returned parse objects and stuff them in to a Word through its constructor. This allows us to call regular java methods on the Word object and not worry about string based field names.
That basically covers the general mode of working with Parse and documents how the application I have presented as a usecase is implemented.
This is just scratching the surface with Parse. This is probably about a fourth or fifth of what parse offers. I wont have space or time to cover all of it here. So i will leave it to you use the parse documentation, which is quite excellent. Also the parse forum is one of the best I have seen including how quick the reponses are.
However I will point out a few things that are worth talking about before completing this article. The approach I have taken for translating parse object to java objects is a very basic one. You may want to consider enhancing it to suit your needs. There are some efforts like ParseFacade and BAASFacade that are trying to do this lot more cleverly and less code and more type safely. Consider those options and see how they fit the bill. For instance BAASFacade not only provides a facade for parse backend but also to other sources/sinks such as StackMob and even local SQLLite!
Another key drawback with straight parse objects is they don't provide a way to serialize them to strings. This is a problem when you try to pass them through intent extras to other activities. With out this ability you only have two options. Either completely convert them to plain java objects and then pass them through intent firewalls or pass the id of the object across and requery the real object based on its ID. Hopefully with caching properly tuned the later option may not be that bad. But it is unanatural that you have an object in hand but can't use it because you can't pass it to another activity through an intent.
Also keep in mind that you can use JSON to serialize plain java objects quite effectively and transport them as intent extras. However note that ParseObjects cannot be converted to JSON strings. The previous article I have on JSON for local storage is equally applicable for implementing parcelables. Yes JSON is a bit verbose than pure parcelables that are hand coded. However if your objects are small this approach works really well and saves you a lot of error prone code doing otherwise. A link to the JSON article is provided in the references section as well.
In an upcoming article I will provide a reasonable work around where by I will show you a middle of the road approach to use ParseObjects directly for parceling. If you can't wait you can look at the downloadable project for this article and you can see how the parse object wrapper is enhanced to implement parcelable and makes the necessary provisions to make this approach work.
As I have implemented this sample application I have made a lot of use of the form processing framework I wrote about in an earlier article. You will see a link to this in the references section as well. This saved me a lot of time as this application has a number of forms to login, signup, create words etc.
Further References for this article are available on the top right of this page. I will post a link to the downloadable project soon!!