You are on page 1of 16

Parse cloud-based services for Android apps

Cloud store and query users, data objects, and files in your
Android applications
C. Enrique Ortiz
Mobile Technologist
Independent

Skill Level: Intermediate


Date: 20 Nov 2012

Explore the advantages of storing mobile application data in a private cloud with
this introduction to the Parse SDK for Android. Mobilist C. Enrique Ortiz introduces
the Parse API classes for cloud-storing and manipulating users, data objects, and
files for your mobile applications.
The Parse mobile SDK provides cloud-based APIs and services for iOS, Android,
and Windows applications. Parse SDK also provides a JavaScript and REST
APIs. Using the Parse API, you can cloud-enable your mobile applications very
quickly and with minimal effort. A mobile application that is integrated with the Parse
API can easily store data objects and files on the Parse cloud, send and listen to
push notifications, manage users, handle geo-location data, and use social media
platforms such as Twitter and Facebook. For mobile applications that need to scale,
the Parse SDK offers all the elasticity of a cloud platform.
Before you start
I assume for the purposes of this article that you are already familiar with
the basic concepts required to program mobile apps with JSON, Android,
and Eclipse. Before you read any further, go to Parse.com and define your
application. Just follow the simple instructions starting from the sign-up
page.

This article introduces the core Parse API classes for Parse users, data objects, and
files. You'll learn how to work with access control lists (ACLs) and how to perform
CRUD operations on data objects, and how to store and retrieve files in the Parse
cloud. Examples are built on the Parse SDK for Android (see Resources).

The Parse dashboard


The Parse dashboard assists developers in managing applications. The dashboard
provides general and application-specific usage metrics for APIs and file and push
Copyright IBM Corporation 2012
Parse cloud-based services for Android apps

Trademarks
Page 1 of 16

developerWorks

ibm.com/developerWorks/

notifications. Application keys and settings are managed via the dashboard. The
dashboard also provides a data browser that allows developers to browse and even
edit stored Parse objects. The data browser is very useful for debugging. Figure 1 is
a screenshot of the Parse dashboard:
Figure 1. The Parse dashboard

Applications are authenticated via an application ID and a client ID. To get your
application and client IDs, you must register your application via the Parse
dashboard. You will use these keys when initializing the Parse library on your app.

Parse data objects


In Parse, data is represented using ParseObject, a container of name-value pairs.
ParseObject can store any data that is JSON-compatible, as shown in Listing 1:
Listing 1. A ParseObject example
ParseObject myParseObject = new ParseObject("MyObject"); // Class Name
myParseObject.put("name", "C. Enrique Ortiz");
myParseObject.put("twitterHandle", "eortiz");
myParseObject.put("followers", 123456);

ParseObject is given a classname when instantiated. The classname in Listing 1 is


"MyObject." Classnames are like table names in a relational database, and Parse

objects of the same class are like rows within a table.

exposes methods similar to the ones found in a Java Map class,


such as put, get, and remove, plus a number of other methods that are specific to
ParseObject.
ParseObject

name keys must be alphanumeric; as a guideline, use camel-casing


for name keys. Values can be of any data type that can be stored in JSON; that is,
numbers, strings, booleans, arrays, JSONObject.NULL, JSONObjects, and JSONArrays.
Other data types supported by ParseObject are Java Date and byte[] arrays. A
ParseObject may also include other ParseObjects.
ParseObject

Parse cloud-based services for Android apps

Page 2 of 16

ibm.com/developerWorks/

developerWorks

Listing 2 shows some of the supported ParseObject value data types:


Listing 2. ParseObject: Some supported value data types
// Byte Array
byte[] byteArray = {1, 2, 3, 4, 5};
// A date
Date d = new Date(); // java.util.Date
// A number
int number = 21;
// A String
String name = "Enrique";
// A JSONArray - any mix of JSONObjects, JSONArrays, Strings, Booleans,
//
Integers, Longs, Doubles, null or NULL.
JSONArray jArray = new JSONArray();
jArray.put(number);
jArray.put(name);
// A JSONObject
JSONObject jObject = new JSONObject();
try {
jObject.put("number", number);
jObject.put("name", name);
} catch (JSONException e) {
e.printStackTrace();
}
// A ParseObject
ParseObject pObject = new ParseObject("MyObject"); // Class name
pObject.put("myByteArray", byteArray);
pObject.put("myDate", d);
pObject.put("myString", name);
pObject.put("myNumber", number);
pObject.put("myJsonArray", jArray);
pObject.put("myJsonObject", jObject);
pObject.put("myNull", JSONObject.NULL);

The code in Listing 2 creates a ParseObject which is stored as an object in the Parse
cloud. Many MyObjects of the same class are then stored as rows of ParseObject
data objects that can be saved, queried for, updated, and deleted from Parse's
cloud storage. It's even possible to save data when the application is offline the
Parse library simply saves the data locally until a network connection has been reestablished.
Modifying a ParseObject
If you are familiar with mobile application development, then you know that long
operations such as network operations should typically be done in the background,
on a worker thread and not on the main system UI thread. This keeps the main
system thread from blocking and affecting the responsiveness of your user interface.
Later in the article, I'll show you how Parse facilities work in the background to save,
delete, and find objects. For now, consider the following synchronous remove()
method, which is used to remove a key from the Parse object:
pObject.remove("myNumber"); // remove the field/key "myNumber" from pObject

Parse cloud-based services for Android apps

Page 3 of 16

developerWorks

ibm.com/developerWorks/

After removing or adding fields, or updating a current field, you can save (or update)
the data object on the cloud by calling one of the ParseObject's save...() methods,
which I discuss later in the article.
Summary: ParseObject
ParseObject represents a data object on the Parse cloud. It provides
methods to add name-value pairs, test whether a given key is present, and
delete or fetch a given ParseObject from the server. ParseObject also
lets you use various get...() and put...() methods to manipulate
ParseObject data, merge ParseObjects, save a ParseObject in the
server, and more.

Parse users, roles, and ACLs


Before I show you how to perform CRUD operations on a Parse object, you should
know some things about Parse users, roles, and ACLs (access control lists). All
three are very important concepts and facilities for protecting your application's data
objects.
Parse users
A class called ParseUser represents a user and provides user-account functionality
for Parse applications. Every Parse application has Parse users associated with it. A
ParseUser is a ParseObject but with the additional properties of username, password,
and email. You can add any additional data values as you see fit.
Anonymous users in Parse
An anonymous user in Parse is one without a username or password.
Anonymous users are useful for mobile application functionality that doesn't
require user authentication. Anonymous users can create data objects, but
such objects are short-lived and won't be available once the anonymous
user logs out.

Users may sign up as Parse users of your app, as shown in Listing 3:


Listing 3. ParseUser signup
ParseUser user = new ParseUser();
user.setUsername("eortiz");
user.setPassword("123456");
user.setEmail("eortiz@nospam.com");
user.put("userType", "Author"); // add another field
// Call the asynchronous background method to sign up
user.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
// Successful. Allow access to app.
} else {
// Failed....
}
}
});

Parse cloud-based services for Android apps

Page 4 of 16

ibm.com/developerWorks/

developerWorks

The username and email must be unique. If a username or email is already in use,
the sign-up call will fail. You should have a mechanism to notify the user if either field
fails, as well as a process for trying again.
After signup, users can log in to your app, as shown in Listing 4:
Listing 4. ParseUser log in
ParseUser.logInInBackground("eortiz", "123456", new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
// Successful. Allow access to app.
} else {
// Failed
}
}
});

You can update user information by calling ParseUser.save(). Note, however, that
only the owner of ParseUser can modify its content; for everyone else, the data is
read-only.
Parse caches the currently logged-in user. You can query the current user by calling
ParseUser.currentUser(). The currentUser method allows you to quickly access
current user information, so that you need only prompt for credentials if the current
user session is not active. Listing 5 show how to retrieve a current user in Parse:
Listing 5. ParseUser getting the current user
ParseUser currentUser = ParseUser.getCurrentUser();
if (currentUser != null) {
// current user is valid
} else {
// current user not valid, ask for credentials
}

Resetting a current user


You can reset a current user in Parse by calling ParseUser.logOut(), as shown in
Listing 6:
Listing 6. ParseUser resetting current user (log out)
ParseUser.logOut(); // static method

Parse ACLs
An ACL is a list of access permissions (or controls) that are associated to a
data object. The ParseACL class allows you to define the permissions for a given
ParseObject. With ACLs, you can define public access to your application data
objects and you can limit access to specific users or groups of users (via roles).
Listing 7 demonstrates the use of Parse ACLs:
Listing 7. Using ParseACL for access permissions
// Define a Parse user
ParseUser user = new ParseUser();

Parse cloud-based services for Android apps

Page 5 of 16

developerWorks

ibm.com/developerWorks/

user.setUsername(username);
:
:
// Define a read/write ACL
ParseACL rwACL = new ParseACL();
rwACL.setReadAccess(user, true); // allow user to do reads
rwACL.setWriteAccess(user, true); // allow user to do writes
:
:
// Define a Parse object and its ACL
ParseObject gameObject = new ParseObject("Game");
gameObject.setACL(rwACL); // allow user do read/writes on gameObject
gameObject.saveInBackground(); // save the ACL'ed object to the cloud
:
:
// You can define a public ACL that gives public access to the object
ParseACL publicACL = new ParseACL();
publicACL.setPublicReadAccess(true);
publicACL.setPublicWriteAccess(true);
gameObject.setACL(publicACL); // allow public read/writes
gameObject.saveInBackground(); // save the ACL'ed object to the cloud

You can also define a default ACL for all newly created objects. In Listing 8 I have set
the default ACL to be public for reads and writes, as defined by publicACL in Listing
7.
Listing 8. Setting default ACL
// Set a default ACL for all newly created objects as public access
ParseACL.setDefaultACL(publicACL, true);

While not shown here, we could also use the ParseRole class to grant access
permissions to groups of users.
Next, we'll look at how Parse data objects are saved to and retrieved from the Parse
cloud.

Parse data objects on the cloud


Once you have created and populated a ParseObject, you can save it on the Parse
cloud. Saving data objects on the Parse cloud is actually one of the simplest things
to do with Parse; the complexity that is usually associated with data representation,
marshaling, network communication and transport, and so on, is completely hidden
by Parse. You'll need to use helper methods to map your data object instance into a
ParseObject and back, and you'll need to decide whether you want to dispatch the
Parse save operation on your own thread or use the save-in-the-background method.
Beware of blocking the system thread!
Recall that in mobile apps, long operations such as network, file, or long
computations should not be done on the main system thread. Instead,
execute them under a separate worker thread. Blocking the system thread
would negatively affect the app's UI responsiveness, potentially resulting in
your application being forcibly closed.

Parse cloud-based services for Android apps

Page 6 of 16

ibm.com/developerWorks/

developerWorks

ParseObject provides two kinds of save methods: save() and saveInBackground().


saveInBackground() is the recommended save method as it runs the save operation
on its own worker thread. If you choose to use the synchronous save() method, be

aware that it is your responsibility to call this method on its own worker thread to
prevent the UI from blocking.
Listing 9 shows the code to save a Parse data object in the background:
Listing 9. Save ParseObject in the background
// ParseObject
ParseObject pObject = new ParseObject("ExampleObject");
pObject.put("myNumber", number);
pObject.put("myString", name);
pObject.saveInBackground(); // asynchronous, no callback

And Listing 10 shows the code for saving a Parse data object the background with a
callback:
Listing 10. Save in the background with callback
pObject.saveInBackground(new SaveCallback () {
@Override
public void done(ParseException ex) {
if (ex == null) {
isSaved = true;
} else {
// Failed
isSaved = false;
}
}
});

Variations of the save...() method include the following:


saveAllinBackground() saves a ParseObject with or without a callback.
saveAll(List<ParseObject> objects) saves a list of ParseObjects.
saveAllinBackground(List<ParseObject> objects) saves a list of
ParseObjects in the background.
saveEventually() lets you save a data object to the server at some point in the
future; use this method if the Parse cloud is not currently accessible.
Once a ParseObject has been successfully saved on the Cloud, it is assigned a
unique Object-ID. This Object-ID is very important as it uniquely identifies that
ParseObject instance. You would use the Object-ID, for example, to determine if
the object was successfully saved on the cloud, for retrieving and refreshing a given
Parse object instance, and for deleting a particular ParseObject.

Retrieving data objects from the cloud


This section looks at methods to query and retrieve data objects stored on the Parse
cloud. You can query a single ParseObject by object-ID, or you can query for one
Parse cloud-based services for Android apps

Page 7 of 16

developerWorks

ibm.com/developerWorks/

or more Parse objects using attributes. If you already have a ParseObject, you can
refresh or synchronize its contents by fetching the latest values from the server. We'll
look at all of these options in the following code snips.
Fetching ParseObjects
To fetch a data object from the Parse cloud, use the ParseObject method fetch() or
fetchInBackground(), shown in Listing 11:
Listing 11. Fetching (unconditional)
// ParseObject
ParseObject pObject = new ParseObject("ExampleObject");
:
:
// Fetch the parse object unconditionally
try {
pObject.fetch();
} catch (ParseException e) {
e.printStackTrace();
}
// Fetch the parse object unconditionally, with Callback
pObject.fetchInBackground(new GetCallback() {
@Override
public void done(ParseObject obj, ParseException ex) {
if (ex == null) {
// Success
} else {
// Failed
}
}
});

You can also fetch only if needed; for example, when fetching a Parse object that has
related Parse objects, as in Listing 12:
Listing 12. Fetching as needed
ParseObject po = new ParseObject("ExampleObject");
:
ParseObject po2 = po.getParseObject("key");
// Fetch only if needed
try {
po2.fetchIfNeeded();
} catch (ParseException e) {
e.printStackTrace();
}

Another option is to do a fetch-if-needed operation in the background


and with a callback. For this, you would use the Parse object method
fetchIfNeededInBackground(GetCallback callback).
In some cases, you will need to fetch a collection of Parse objects at one time,
unconditionally, or only if needed. ParseObject provides a set of static methods for
Parse cloud-based services for Android apps

Page 8 of 16

ibm.com/developerWorks/

developerWorks

this; each one takes for input a list of Parse objects and then returns a list of Parse
objects:
fetchAll(List<ParseObject> objects)
fetchAllIfNeeded(List<ParseObject> objects)
fetchAllIfNeededInBackground(List<ParseObject> objects, FindCallback
callback)
fetchAllInBackground(List<ParseObject> objects, FindCallback callback)

Querying data objects on the cloud


Hopefully you've seen by now that the Parse API is super comprehensive but
wait, there's more! In addition to fetching data objects, Parse also lets you query data
objects using object-ID or attributes. To query a data object from the Parse cloud,
use ParseQuery. You can use ParseQuery for both basic and complex data queries,
receiving back a given object or a List of matching objects.
Listing 13 shows how to retrieve a specific Parse object from the server in a
background thread, given an object-ID:
Listing 13. Using ParseQuery to retrieve a given ParseObject
String myID = "12345";
ParseQuery query = new ParseQuery("Players");
query.getInBackground(myID, new GetCallback() {
@Override
public void done(ParseObject object, ParseException e) {
if (object != null) {
// Get object
} else {
// Not found
}
}
});

Note that query.getInBackground() does not use the ParseQuery cache.


Listing 14 shows a query that retrieves all data objects of class: Players. (No
constraint provided.)
Listing 14. Using ParseQuery to all ParseObjects of a given class
ParseQuery query = new ParseQuery("Players");
query.findInBackground(new FindCallback() {
@Override
public void done(List<ParseObject> players, ParseException e) {
if (players != null) {
// Get list of players
} else {
// No players
}
}
});

In Listing 15 I've used a query constraint to retrieve one or more matching Parse
objects; in this case active Players:
Parse cloud-based services for Android apps

Page 9 of 16

developerWorks

ibm.com/developerWorks/

Listing 15. Using ParseQuery to retrieve matching ParseObjects

ParseQuery query = new ParseQuery("Players");


query.whereEqualTo("status", "active");
query.findInBackground(new FindCallback() {
@Override
public void done(List<ParseObject> players, ParseException e) {
if (players != null) {
// Success - players contain active players
} else {
// Failed
}
}
});

also provides a method to get the count of matching objects without


retrieving the objects themselves, which is very useful. Listing 16 shows how to get
the count of active players:
ParseQuery

Listing 16. Using ParseQuery to count matching ParseObjects


ParseQuery query = new ParseQuery("Players");
query.whereEqualTo("status", "active"); //remove this line to count ALL
query.countInBackground(new CountCallback() {
@Override
public void done(int count, ParseException e) {
if (e == null) {
// Success, see count variable
} else {
// Failed
}
}
});

ParseQuery methods and constraints


ParseQuery

examples:

supports more than 20 different query-constraint methods; here are some

whereMatches(String key, String regex) finds string values that match the
provided regular expression.
whereStartsWith(String key, String prefix) finds string values that start
with a provided string.
whereContains(String key, String substring) finds values that contain a
provided string.
whereGreaterThan(String key, Object value) finds values that are greater
than the provided value.
whereWithinKilometers(String key, ParseGeoPoint point, double
maxDistance) finds objects with point values near the point given and within the
maximum distance given.
Query results can be ordered, as shown in Listing 17. To order query results, call one
of the query orderBy...() methods, specifying the field to order by.
Parse cloud-based services for Android apps

Page 10 of 16

ibm.com/developerWorks/

developerWorks

Listing 17. Ordering query results


query.orderByAscending("name");
query.orderByDescending("name");

For example:

ParseQuery query = new ParseQuery("Players");


query.whereEqualTo("status", "active");
query.orderByAscending("lastName"); // By lastname ascending order
query.findInBackground(new FindCallback() {
@Override
public void done(List<ParseObject> players, ParseException e) {
if (players != null) {
// Success - players contain active players
} else {
// Failed
}
}
});

Something else to note is that ParseQuery results are cached. You can set the querycache policy in various ways depending on your application needs. The following
cache policies are currently supported:
IGNORE_CACHE: Do not use the cache; this is the default cache policy.
CACHE_ONLY: Only load from the cache. If there are no cached results, there will
be a ParseException.
NETWORK_ONLY: Always go to the network, but save results to the cache.
CACHE_ELSE_NETWORK: Hit the cache first. If that fails, load from the network. If
neither cache nor network succeed, the result will be a ParseException.
NETWORK_ELSE_CACHE: Hit the network first. If that fails, load from the cache. If
neither network nor cache succeed, the result will be a ParseException.
CACHE_THEN_NETWORK: Hit the cache first, then load from the network. Note that
the FindCallback will actually be called twice: first with the cached results, then
with the network results. This policy can only be used asynchronously with
findInBackground.
Setting the cache policy is simple. Do it before calling the find...() method, as
shown in Listing 18:

Parse cloud-based services for Android apps

Page 11 of 16

developerWorks

ibm.com/developerWorks/

Listing 18. Managing the CachePolicy


ParseQuery query = new ParseQuery("Players");
query.setCachePolicy(ParseQuery.CachePolicy.NETWORK_ELSE_CACHE);
query.findInBackground(new FindCallback() {
@Override
public void done(List<ParseObject> players, ParseException e) {
if (e == null) {
// Success - players contain active players
} else {
// Failed
}
}
});

The ParseQuery class provides all the methods needed to query for data objects that
are stored on the cloud. With ParseQuery, you can specify query constraints of all
kinds, count matching data objects, set limits, skip data objects, order by, clear the
cache, and much more.

Removing data objects


Removing a data object from the Parse cloud is also very simple. Once you have the
object instance, you can delete an existing ParseObject from the cloud by calling the
ParseObject method delete() or deleteInBackground(). Both are shown in Listing
19:
Listing 19. Removing a Parse object from the cloud
parseObject.delete();
parseObject.deleteInBackground();

As you might anticipate, delete() is a blocking call, meaning that it is your


responsibility to properly dispatch this call on its own worker thread. Or you can
let Parse take care of threading by using deleteInBackground() with or without a
callback.

Working with files


Up to this point, we have been working with Parse objects and Parse queries.
I have also introduced you to Parse users, ACLs, and roles. I'll conclude with a
demonstration of working with file read, write, and save functions in Parse.
Recall that you can store raw byte[] data within a ParseObject, which is fine for small
amount of data. When storing larger items such as images or documents, use Parse
Files.
Files in the Parse cloud are represented using ParseFile, which provides methods
to get the name of a file, its URL, and the file data itself, assuming it's available. You
can also download and upload files and access some other helper methods.
Parse cloud-based services for Android apps

Page 12 of 16

ibm.com/developerWorks/

developerWorks

File data is represented by the byte[] syntax. Note that currently, a given file cannot
be larger than 10MB. When naming a file, the Parse library takes care of potential
name collisions. Providing a file extension helps Parse handle file content.
Listing 20 demonstrates saving a JPG file:
Listing 20. Saving a ParseFile
// Save image file
Drawable drawable = ...;
Bitmap bitmap = (Bitmap)((BitmapDrawable) drawable).getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] data = stream.toByteArray();
ParseFile imageFile = new ParseFile("image.jpg", data);
imageFile.saveInBackground();

The initial statements in Listing 20 convert the bitmap into a byte[]. The byte[]
is then saved using a ParseFile saveInBackground() method, similar to how a
ParseObject is saved on the server.
Once the file has been saved on Parse, it must be associated with (put into) a
ParseOject. In other words, Parse files are not true standalone objects and to be
retrieved and used later on, it must be associated with a given ParseObject instance.
This limitation might be addressed on a future release of Parse. Listing 21 associates
the image file with a Player Parse object:
Listing 21. Associating a ParseFile with a ParseObject
// Associate image with Parse object
ParseObject po = new ParseObject("Players");
po.put("name", "eortiz");
po.put("photo", imageFile);
po.saveInBackground();

I have associated the file with the data object, then saved the object on the server
using saveInBackgroud(), which I previously discussed.
Listing 22 shows how to retrieve a file that is associated with a data object:
Listing 22. Retrieving the ParseFile
// Retrieving the file
ParseFile imageFile2 = (ParseFile)po.get("photo");
imageFile2.getDataInBackground(new GetDataCallback() {
public void done(byte[] data, ParseException e) {
if (data != null) {
// Success; data has the file
} else {
// Failed
}
}
});

After receiving a ParseFile reference from the Parse object, I called


getDataInBackground() to retrieve the ParseFile from the servers. Note that I used
Parse cloud-based services for Android apps

Page 13 of 16

developerWorks

ibm.com/developerWorks/

the callback GetDataCallback to retrieve the Parse files, as opposed to GetCallback,


which is for retrieving Parse objects with ParseQuery.

In conclusion
The Parse API is very comprehensive and includes classes for accessing mobile
services such as push notification, using geo-data, integrating with social media
platforms, and more. In this article, I've scratched the surface of what you can do with
Parse by introducing the Parse APIs for data and file cloud storage. Knowing how to
store and manipulate Parse users, data objects, files, and ACLs in the Parse cloud is
good foundation for further exploring this cloud platform for mobile development.
Acknowledgments
Many thanks to Athen O'Shea for his review of this article.

Parse cloud-based services for Android apps

Page 14 of 16

ibm.com/developerWorks/

developerWorks

Resources
Learn more about the Parse Android SDK; also see the Parse Quick Guide to
choose a mobile platform, set up an app, and download and install your Parse
SDK.
View a complete listing of the Parse Android APIs.
"Develop Android applications with Eclipse (Frank Ableson, developerWorks,
February 2008): Get more practice developing Android apps in the Eclipse
development environment, this time using the Android Eclipse plug-in.
"Introduction to jQuery Mobile" (C. Enrique Ortiz, developerWorks, May 2012):
Learn the basics of jQuery Mobile and how to write a functional mobile web
application user interface. Working examples guide you through pages,
navigation, toolbars, list views, form controls, and transition effects in jQuery
Mobile.
"Solve your many-device-to-many-platform mobile application integration
challenges" (Olivier Picciotto, developerWorks, August 2012): Mobile
development and cloud computing are practically inseparable these days, but
integrating mobile applications into the cloud is still new territory. Learn how the
mobile enterprise application platform (MEAP) solves some mobile-to-cloud
integration challenges.
"DevOps for mobile development" (Michael Rowe, developerWorks, July 2012):
Companies all over the world want to exploit the mobile market by providing
customers and users with apps that make mobile computing easier. This
article thinks through some of the technical and business issues involved with
integrating development and operations for mobile platforms in the workplace.
Follow developerWorks on Twitter.
Watch developerWorks on-demand demos ranging from product installation
and setup demos for beginners, to advanced functionality for experienced
developers.
Get involved in the developerWorks community. Connect with other
developerWorks users while exploring the developer-driven blogs, forums,
groups, and wikis.

Parse cloud-based services for Android apps

Page 15 of 16

developerWorks

ibm.com/developerWorks/

About the author


C. Enrique Ortiz
C. Enrique Ortiz is a longtime mobilist, author, and blogger who was
creating end-to-end mobile software before smartphones were smart.
He has written many technical articles and two books on mobile
software development, and he has helped dozens of companies with
their mobile computing needs.
Copyright IBM Corporation 2012
(www.ibm.com/legal/copytrade.shtml)
Trademarks
(www.ibm.com/developerworks/ibm/trademarks/)

Parse cloud-based services for Android apps

Page 16 of 16

You might also like