10
Google IO Session Overview: Android + App Engine: A Developer’s Dream Combination
62 Comments · Posted by Brad Abrams in Uncategorized
Xavier Ducrohet and I had a great time today demoing “BigDaddy” which is the codename for the Google Plugin for Eclipse 2.4 Beta that we released today.
I started off with the following products installed:
Eclipse Helios, Android Developments Tools and, of course the Google Plugin for Eclipse 2.4 beta.
- See the video of the talk: http://www.youtube.com/watch?v=M7SxNNC429U
- Download the complete source code for the demo: https://code.google.com/p/cloud-tasks-io
- See the demo live (but please only use test data): http://cloudtasksio.appspot.com. For the Android client, browse to the bottom of this page on your phone to find the link to the APK.
- You can also check out the default Big Daddy application: http://bigdaddy-io.appspot.com/
- Access the slides http://www.slideshare.net/brada/androidandroid-app-engine-a-developers-dream-combination
Our goal is to create a task tracking application for Larry Page. As he takes over as CEO, Larry has a lot of tasks that he needs to track and this app will help him (and the rest of us) track tasks. ;-)
The basic architecture of the task app looks very similar to a wide range of applications

First, we have an Android application that talks, via RPC to an App Engine server where your business logic is and the data is stored in the app engine datastore. We also needed a standards based web client that can work from anywhere on the same data with the same business logic. We built that out with GWT to keep with the same programing language and tools, but of course, any web client technology will work. Finally, we use C2DM to do push notification when new tasks are added to the database.
OK, so let’s look at how we build this task tracking application.
The first step is to create a new App Engine Connected Android Project. This project gives you a very useful starting project with the plumbing code in libraries and the code that you may want to change and tweak generated into the project. This project gives you a few things:
1. An authenticated Hello world RPC service with the logic in app engine and clients in GWT and Android.
2. All the C2DM infrastructure .
a. App Engine based datastore for handing registration
b. Android client with default UI for picking a user and responding to C2DM messaging
c. GWT based client for sending C2DM pings through the app engine server.
Let’s take a look at how this works.
Creating the Starter Project
In Eclipse select File\New then Other. Under the Android node you will find the “App Engine connected Android project”.

In the first page of the wizard, simply give your project a name and namespace. From these the tool will create Android, App Engine and GWT projects.

note: if you see the warning to “configure Android SDK” just click on the link and select the Android SDK with at least API level 8 (to support C2DM). You will also likely want to select an a Google APIs enabled SDK to support the google authentication that we will be using.
The next page of the wizard asks for your C2DM role account. You can sign up for a C2DM role account from this wizard.

A tip: You can auto fill this in if you put a file called c2dm.properties in your home directory with the format:
user=yourid@gmail.com
passwd=yourpassword
This wizard creates two projects… An Android client and App Engine server. Along with a shared code directory for storing code that is compiled into both projects.

To run this, you will want to connect your android phone via USB or create an virtual device via the Android SDK and AVD manager and launch it. For the AVD I found targeting google API level 9 and 256 meg SD card more than sufficient. I used a screen size of 9 to be small enough to manage, but still readable. I also found that saving a snapshot once after boot then only launching from snapshot NOT having to the snap shot made testing on a clean image with a very fast start-up helpful.

You can verify you have your device connected by looking at the DDMS perspective in eclipse. You should see your emulator up and the list of all the process. This indicates that you are ready to go.

Running the Starter Project
Once you have a device connected, you right click on the Android project and select Debug As then Local App Engine Connected Android Project.

What this does is wire up the android application to talk to the local app engine dev app server.
In the emulator, we see the application pop up. The first thing it asks you to do is log in (if you don’t see it, click options and then accounts). This very important — many android devices have google accounts built in. A coworker of mine recently told me he’d rather stand naked in the rain than type his password on the phone. Using the google accounts makes it possible to authenticate without typing a password. This will also enable authenticated RPCs and C2DM pings as you will see.

Once you connect, your device will be registered to receive C2DM messages. In particular, the app engine application with store a unique code for pinging your device when a message is sent to you. You can look in the app engine datastore to see exactly what the app engine application is storing for you. Browse to http://127.0.0.1:8888/_ah/admin/ and select DataStore viewer.
As you can see here, we store the user’s email address and the unique device ID. This allows us to send C2DM pings through the App Engine server later.

Back in the Android client, click on the Say Hello button, you will see a message back from the app engine server. It calls the getMessage() functional found in the HelloWorldService.java file in the com.cloudtasks.server package. Notice that it is return the user’s email address from the server. That is fantastically cool. It means that the app engine server knows the same user identity information as the android client.
public static String getMessage() {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
String message;
if (user == null) {
message = "No one is logged in!\nSent from App Engine at " + new Date();
} else {
message = "Hello, " + user.getEmail() + "!\nSent from App Engine at " + new Date();
}
log.info("Returning message \"" + message + "\"");
return message;
}

Also, once that C2DM registration is successful, you get a C2DM ping. This is unlikely the right user experience for your application when completed, but it is a good, clear way to start and is very easy to update.

Now, let’s take a look at the standards based web client that is written in GWT. You can start this up by flipping to the Development Mode tab and click on the URL there.

That will launch a web browser. If you have not installed the GWT plugin for development mode only you will need to. Notice that in production it is just javascript no plugin required.
Now you will see the local app engine test log in experience. This is because we have setup the default project to require authentication. That is down in the App Engine project under war/web.xml. Notice this section:
<security-constraint>
<web-resource-collection>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
This indicates that all urls in this project require authentication.

You could easily add another node if you wanted some unsecured access URLs for general information, etc. See the App Engine documentation for more information. This functionality enables you to “log in” with any email address when running in test mode. Notice no password is required because this is just a test model. When deployed to app engine this will be replaced with the typical Google log in dialog. See more information. We log in with the same email address as we used on the android client. That will be important later when we share data.
In the GWT application, we have the same “Say Hello” button. Click on it does the RPC round trip to the server. Already we are sharing identity and business logic between the android client, the GWT web front end and the App engine based server.

Sending a C2DM Ping
Now, let’s send a C2DM ping.
Notice I use the same email address as I logged into my Android phone with.

Then I flip over to the phone and presto… A C2DM message arrives.

So that is basically what is in the starter app. A very solid way to get started!
Want to try it live yourself? Check out the running app here:
http://bigdaddy-io.appspot.com/
You can install the APK from this site on your phone.
Be sure to log in to the android app before you test sending C2DM pings
Tasks Data Layer and RPC Layer
Now let’s focus on building out the custom logic for our task tracking application for Larry Page.
First we will need a task entity. We will just create a new java class in the app engine server project in the com.cloudtasks.server package.
Here is a snippet of it.. a very simple java class with no data access logic.. Just fields and accessors.
@Entity
public class Task {
private String name;
private String notes;
private Date dueDate;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String userId;
private String emailAddress;
public Task () {}
public String getName() {
return name;
}
Now we need to create our Service class. This is the place we want to write our shared business logic that can be called from the GWT client and the Android client via JSON over http.
We do this with the new RPC tooling wizard in GPE 2.4. Right click on the com.cloudtasks.server project, select New and then Other and find the “RPC Service” under the Google directory.

As you can see, the wizard looks in your server project for all the entities (marked with an attribute of “@Entity” or “@PresistenceCapable”). The wizard will create Query + Create, Update and Delete methods for each entity you select. You can add more custom methods, add custom params, etc in the code. The wizard will also generate custom code in the com.cloudtasks.shared directory for calling the this service. We will see that code a bit later.

Now, let’s flush this out a bit. One of the beautiful parts of this system is that by the time the caller gets to one of these methods you the serialisation, authentication and validation is complete. In other words, all the plumbing code is gone. You simply need to implement your storage logic. You can use any store you want from some legacy system, to S3. But of course we will show how to use App Engine’s Datastore.
I wrote a simple data layer that uses JDO to store entities. I called the class DataStore.
First, let’s create an instance of the DataStore:
public class CloudTasksService {
static DataStore db = new DataStore();
Then let’s handle implementing the queryTasks() method. As you can see, it is pretty simple.
public static List<Task> queryTasks() {
return db.findAll();
}
But let’s take a look at what that db.findAll() method does.
public List<Task> findAll() {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Query query = pm.newQuery("select from " + Task.class.getName()
+ " where emailAddress=='" + getUserEmail() + "'");
List<Task> list = (List<Task>) query.execute();
if (list.size() == 0) { //workaround for known issue
list.size();
}
return list;
} finally {
pm.close();
}
}
Notice that query.. the App Engine datastore is a highly scalable no-sql database, but you can do sql-like queries over it. In this case, we are looking at the task items, but only those where the emailAddress of the task matches that of the currently logged on user. So even thought we are storing all the tasks in a single datastore, a given user can only ever access their own tasks. Notice again how the common notion of identity between app engine and Android really helps us out.
Delete is pretty much what you’d expect. We actually do delete the item from the datastore, but you could of course use some sort of tombstoning technique if you’d like.
public static void deleteTask(Task task) {
db.delete(task.getId());
}
But update is more interesting
public static Task updateTask(Task task) {
task.setEmailAddress(DataStore.getUserEmail());
return db.update(task);
}
As you can see, here we are not just updating the task, but we are also tromping over whatever email address the user sent in. We are doing this to ensure that no one else tries to submit a task with Larry Page’s email address. Of course our clients would not allow that, but remeber this is just Json over http, so some rouge client cloud.
The implementation of getUserEmail() is also very basic… again leveraging the power app engine knowing about google identities.
public static String getUserEmail() {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
return user.getEmail();
}
The implementation of db.update() is also very basic. The hard work is all handed by app engine.
public Task update(Task item) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(item);
return item;
} finally {
pm.close();
}
}
The implementation of create and read are also very simple.
public static Task createTask() {
return db.update(new Task());
}
public static Task readTask(Long id) {
return db.find(id);
}
Notice in createTask() we round trip the task the datastore in order to get a unique ID for it, such that update can work later.
While this was very simple, it is also very scalable… we have app engine customers storing hundreds of millions of entities using this same pattern.
Basic GWT Web Client
OK.. I think we are ready to build the Android app out, but before we do, we hand better do a quick test of these methods. To do so, I will make some quick modifications to the default GWT web client to simply test each of these methods.
So in com.cloudtasks.client.CloudTasks.java I added buttons for Add, Update, Query and Delete.
From the Create button, we simply call the “createTask” method, this is the client proxy for the createTask method we implemented in the App Engine project. We call it off the TaskRequest class which was generated by the RPC tooling wizard. Notice we use a TaskProxy, that is the client proxy for the Task class in the server project.
private void create() {
TaskRequest request = taskRequestFactory.taskRequest();
request.createTask().fire(new Receiver<TaskProxy>() {
@Override
public void onSuccess(TaskProxy task) {
Window.alert("CREATE SUCCESS:(" + task.getId() + ")" );
taskProxy = task;
}
});
}

Update looks just like you’d expect
private void update(TaskProxy task) {
TaskRequest request = taskRequestFactory.taskRequest();
taskProxy = request.edit(taskProxy);
taskProxy.setName(getTaskName());
request.updateTask(task).fire(new Receiver<TaskProxy>() {
@Override
public void onSuccess(TaskProxy task) {
Window.alert("UPDATE SUCCESS:(" + task.getId() + "): " + task.getName());
}
});
}
Query looks pretty much like you might expect:
private void query() {
taskRequestFactory.taskRequest().queryTasks().fire(
new Receiver<List<TaskProxy>>() {
@Override
public void onSuccess(List<TaskProxy> taskList) {
String names = "\n";
for (TaskProxy task : taskList) {
names += " (" + task.getId() + "): " + task.getName() + "\n";
}
Window.alert("QUERY SUCCESS: Count[" + taskList.size + "] Values:" + names);
}
});
Running it after adding a few more tasks for Larry looks like:

Now that we have the basic data layer and RPC service complete, it is time for Xav to come up and implement the Android client.
Basic Android Client
We have seen a very basic GWT based client, but now let’s look at how to build out the Android client. You will notice it looks very similar to the RPC calling code we have shown above.
The CloudTasksActivity.java class contains the main activity for the application. In onCreate() we setup the list adapter.
TaskApplication taskApplication = (TaskApplication) getApplication();
adapter = taskApplication.getAdapter(this);
listView.setAdapter(adapter);
Then on onStart() we fetch the tasks, passing -1 to indicate that we need to get all the tasks
protected void onStart() {
super.onStart();
// only fetch task on start if the registration has happened.
SharedPreferences prefs = Util.getSharedPreferences(mContext);
String deviceRegistrationID = prefs.getString(Util.DEVICE_REGISTRATION_ID, null);
if (deviceRegistrationID != null) {
fetchTasks(-1);
}
}
Then in CloudTaskActivity.java we click off an async fetch.
public void fetchTasks(long id) {
progressBar.setVisibility(View.VISIBLE);
if (task != null) {
task.cancel(true);
}
task = new AsyncFetchTask(this);
task.execute(id);
}
The AsyncFetchTask fires the RPC to get the task list.
protected List<TaskProxy> doInBackground(Long... arguments) {
final List<TaskProxy> list = new ArrayList<TaskProxy>();
CloudTasksRequestFactory factory = Util.getRequestFactory(activity,
CloudTasksRequestFactory.class);
factory.taskRequest().queryTasks().fire(new Receiver<List<TaskProxy>>() {
@Override
public void onSuccess(List<TaskProxy> arg0) {
list.addAll(arg0);
}
});
return list;
}
The AsyncFetchTask fires the RPC to get the task list.
protected List<TaskProxy> doInBackground(Long... arguments) {
final List<TaskProxy> list = new ArrayList<TaskProxy>();
CloudTasksRequestFactory factory = Util.getRequestFactory(activity,
CloudTasksRequestFactory.class);
factory.taskRequest().queryTasks().fire(new Receiver<List<TaskProxy>>() {
@Override
public void onSuccess(List<TaskProxy> arg0) {
list.addAll(arg0);
}
});
return list;
}
The AsyncFetchTask fires the RPC to get the task list.
protected List<TaskProxy> doInBackground(Long... arguments) {
final List<TaskProxy> list = new ArrayList<TaskProxy>();
CloudTasksRequestFactory factory = Util.getRequestFactory(activity,
CloudTasksRequestFactory.class);
factory.taskRequest().queryTasks().fire(new Receiver<List<TaskProxy>>() {
@Override
public void onSuccess(List<TaskProxy> arg0) {
list.addAll(arg0);
}
});
return list;
}
And we run it and it looks great!

Nice GWT Client
Wow, that Android client looks great, let’s see what we can do to make the GWT client look good as well.
A few updates to HTML and CSS in the CloudTasks-AppEngine\war folder and some updates to the GWT client code in CloudTasks-AppEngine\com.cloudtasks.client, we get a nice looking web client that can be accessed from anywhere.
One tip for GWT development… You don’t need to stop and start GWT Development mode. Simply hit refresh in the browser and see your changes.

Now, we add a new task, but that task does not show up in the Android client until the user manually refreshes it. That is not great – Larry could easily miss tasks he adds via the web page. We could make the Android client poll the server every few minutes for new tasks, but that is a huge battery and network drain on the device, and creates unnecessary load on the server.
Cloud to Device Messaging to the rescue! C2DM allows you send a ping the android client to let it know there are new tasks to pick up. You can’t send a lot of data over this channel, so we will just send the ID of the task to that was updated.
Luckily we have a very convenient place to add this logic on the server. Let’s look at CloudTasksService.java in the CloudTasks-AppEngine\com.cloudtasks.server directory.
public static Task updateTask(Task task) {
task.setEmailAddress(DataStore.getUserEmail());
task = db.update(task);
DataStore.sendC2DMUpdate(TaskChange.UPDATE +
TaskChange.SEPARATOR + task.getId());
return task;
}
First, check out that sendC2DMUpdate() method. The default project makes it very easy to send a C2DM message.
public static void sendC2DMUpdate(String message) {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
ServletContext context = RequestFactoryServlet.getThreadLocalRequest().getSession().getServletContext();
SendMessage.sendMessage(context, user.getEmail(), message);
}
We call the SendMessage class passing the email address of the owner of the task that was updated. Recall that we verified this was not spoofed when we updated the task.
For the messaging, you can see we are using the TaskChange class that we define in the Shared directory. This ensures that the App Engine server and Android client projects share the exact same definition of this class.
To run this, we need to reload the App Engine development time server by clicking the refresh button in the Development Mode tab.

Now, when we run this and add a new task, we get a ping on the Android client.

That is very cool, but the UI isn’t quite right here. We really want to just trigger an RPC call for the task when the C2DM message arrives rather than notifying the user. Luckily that is very easy to do.
In the Android project, in C2DMReceiver.java that the default project generated, we want to remove the notifications message and instead handling it programmatic. To do that we replace the onMessage() implementation as follows.
public void onMessage(Context context, Intent intent) {
TaskApplication app = (TaskApplication) getApplication();
app.notifyListener(intent);
}
The in TaskApplication.java we handle the notification. Notice we use the TaskChange class from the shared code directory that we also used in the App Engine project. To handle it we simply call onTaskUpdated() passing the message which includes the ID of the item being updated.
public void notifyListener(Intent intent) {
if (listener != null) {
Bundle extras = intent.getExtras();
if (extras != null) {
String message = (String) extras.get("message");
String[] messages = message.split(Pattern.quote(TaskChange.SEPARATOR));
listener.onTaskUpdated(messages[0], Long.parseLong(messages[1]));
}
}
}
Finally, we do the actual update:
public void onTaskUpdated(final String message, final long id) {
runOnUiThread(new Runnable() {
public void run() {
if (TaskChange.UPDATE.equals(message)) {
fetchTasks(id);
}
}
});
Now we can see when I add a new task via the web front end, I get the wait icon while an async fetch of that task is done.

then magically the new task just shows up with the minimum of battery life and network.

And of course, this works two way… when you add a new task from the android phone, the browser app automatically updates without a refersh.


Deployment
The final step here is to deploy your application to the production app engine. This is very easy to do from eclipse.
First you go to https://appengine.google.com/ and create an App ID. Go ahead it is free to get started!
Next go to the Android project and find the Setup.java file and update the App name to match the one you just created.
public class Setup {
/**
* The AppEngine app name, used to construct the production service URL
* below.
*/
private static final String APP_NAME = "androidcloudtasks";
Then you click on the App Engine button and select the App Engine Project to deploy.

Next click on App Engine project settings and verify that the correct Application ID is set. Notice you can also change the version string. You can use things like “beta” or “testing” as well as numbers. This helps with the staging, testing, release process.

Then you click deploy. It might take a while for the project to build. GWT creates very optimized javascript for different classes of browsers. Once it is done you should be able to browse to http://yourappid.appspot.com.
Notice that asks you to log in. This is for real, unlike the test client. So you need to give a valid google ID.

Next, App Engine verifies that the user is giving permission for your application to use their email address.

Finally, we see the application running. Notice that you will not see any data at first as this is running against the live App Engine server. You will need to add some tasks here… but once you do you can access them from any web browser anywhere and a nice rich client on your phone!

Summary
Wow – that was a whole load of stuff. Just to review:
1. We created a new App Engine connected Android project with built in support for C2DM and RPC.
2. We add a data layer in App Engine for storing tasks
3. Exposed it over RPC
4. Built an Android client for viewing and updating tasks
5. Built a standards based GWT client for viewing and updating tasks
6. plumbed in C2DM for doing push notifications of new tasks
All in less than 45 mins! Imagine what you can do!
We’d love your feedback on BigDaddy (GPE 2.4)… Please post the the GWT forums or comment here.
No tags
-
http://www.alvinashcraft.com/2011/05/11/dew-drop-may-11-2011/ Dew Drop – May 11, 2011 | Alvin Ashcraft's Morning Dew
-
http://kohlerm.blogspot.com Markus Kohler
-
http://bradabrams.com Brad Abrams
-
Patrick
-
V. Capers Jr.
-
Supreeth
-
Yu-Hsuan Lin
-
http://bradabrams.com Brad Abrams
-
http://bradabrams.com Brad Abrams
-
http://bradabrams.com Brad Abrams
-
https://profiles.google.com/b95505017 Yu-Hsuan Lin
-
http://www.synclio.com Shaun
-
https://profiles.google.com/b95505017 Yu-Hsuan Lin
-
Supreeth
-
Stephen
-
http://sergiodelamo.com Sergio del Amo
-
http://www.spotvite.com Spotvite
-
http://mapsys.info/50299/google-io-a-developer%e2%80%99s-dream-combination/ Google IO: A Developer’s Dream Combination | Mapsys.info
-
http://bradabrams.com Brad Abrams
-
http://bradabrams.com Brad Abrams
-
http://bradabrams.com Brad Abrams
-
http://bradabrams.com Brad Abrams
-
http://weblogs.asp.net/yuanjian/archive/2011/05/16/cheatsheet-2011-05-10-05-16.aspx Cheatsheet: 2011 05.10 ~ 05.16 – gOODiDEA.NET
-
http://bradabrams.com Brad Abrams
-
http://sergiodelamo.com Sergio del Amo
-
Patrick
-
Davy
-
http://bradabrams.com Brad Abrams
-
http://www.bydavy.com Davy
-
Michael Ludwig
-
Franklin
-
Franklin
-
Franklin
-
Yoav
-
http://www.bydavy.com Davy
-
Franklin
-
Jason
-
Malte Jäger
-
Admin
-
Bill Lahti
-
frankzeffi l
-
Anonymous
-
Kelly Elton
-
Josh Clemm
-
Roma
-
mg
-
daniel aranias
-
Ruchita Bora
-
http://twitter.com/charlires Carlos Andonaegui
-
F. Michael
-
Guest
-
Rekha Rupa
-
Vettukal Vincent Mathew
-
Joostwestra
-
DanPride
-
Jens Axelsson
-
Aya Tou
-
Uttamgupta
-
nicolas praetio
-
Andreas
-
http://www.facebook.com/profile.php?id=100003189883764 Dorian Gray
-
Droidsoft

