January 26, 2012
Yosuke Matsuda
Amazon DynamoDB is a fast, highly scalable, highly available, cost-effective, non-relational database service. Amazon DynamoDB removes traditional scalability limitations on data storage while maintaining low latency and predictable performance. The sample mobile application described here demonstrates how to store user preferences in Amazon DynamoDB. Because more and more people are using multiple mobile devices, connecting these devices to the cloud, and storing user preferences in the cloud, enables developers to provide a more uniform cross-device experience for their users.
This article shows sample code for the Android platform. The complete sample code and project files are included in the AWS SDK for Android. Links to the SDK are available at the end of this article.
To use the sample app, you'll need to deploy a token vending machine (TVM). A TVM is a cloud-based application that manages AWS credentials for users of mobile applications. To deploy the TVM, you'll first need to obtain your own AWS credentials: an Access Key ID and Secret Key.
If you haven't already signed up for Amazon Web Services (AWS), you will need to do that first to get your AWS credentials. You can sign up for AWS here. After you sign up, you can retrieve your credentials at this page. The credentials will be used to set up the TVM to authenticate users of AWS mobile applications. Sample Java web applications are available here: Anonymous TVM and Identity TVM (this sample uses Anonymous TVM).
In Amazon DynamoDB, a database is a collection of tables. A table is a collection of items, and each item is a collection of attributes. For our app, we create a single table to store our list of users and their preferences. Each item in the table represents an individual user. Each item has multiple attributes, which include the user's name and their preferences. Each item also has a hash key—in this case, userNo
—which is the primary key for the table.
The app demonstrates how to add and remove users, and modify and retrieve their preference data. The app also demonstrates how to create and delete Amazon DynamoDB tables.
In order to create an Amazon DynamoDB client, we must first register the mobile device with the token vending machine (TVM). For this sample, we use the Anonymous TVM to register the device. Then we store the UID and key returned by the TVM on the device.
RegisterDeviceRequest registerDeviceRequest = new RegisterDeviceRequest(this.endpoint, this.useSSL, uid, key);ResponseHandler handler = new ResponseHandler();response = this.processRequest(registerDeviceRequest, handler);if (response.requestWasSuccessful()) { AmazonSharedPreferencesWrapper.registerDeviceId(this.sharedPreferences, uid, key);} |
The following code demonstrates how to request that the TVM generate temporary credentials, and how to store the returned credentials on the device.
Request getTokenRequest = new GetTokenRequest(this.endpoint, this.useSSL, uid, key);ResponseHandler handler = new GetTokenResponseHandler(key);GetTokenResponse getTokenResponse = (GetTokenResponse) this.processRequest(getTokenRequest, handler);if (getTokenResponse.requestWasSuccessful()) { AmazonSharedPreferencesWrapper.storeCredentialsInSharedPreferences( this.sharedPreferences, getTokenResponse.getAccessKey(), getTokenResponse.getSecretKey(), getTokenResponse.getSecurityToken(), getTokenResponse.getExpirationDate());} |
To make service requests to Amazon DynamoDB, you need to instantiate an Amazon DynamoDB client. The code below shows how to create an Amazon DynamoDB client for Android using the stored temporary credentials from the TVM.
AWSCredentials credentials = AmazonSharedPreferencesWrapper .getCredentialsFromSharedPreferences(this.sharedPreferences);AmazonDynamoDBClient ddb = new AmazonDynamoDBClient(credentials); |
Each user's preferences are stored as items in an Amazon DynamoDB table. The following code creates that table using the client we created above. Every Amazon DynamoDB table require a hash key. In this sample, we use userNo
as the hash key for the table.
AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();KeySchemaElement kse = new KeySchemaElement() .withAttributeName("userNo") .withAttributeType(ScalarAttributeType.N);KeySchema ks = new KeySchema().withHashKeyElement(kse);ProvisionedThroughput pt = new ProvisionedThroughput().withReadCapacityUnits(10l).withWriteCapacityUnits(5l);CreateTableRequest request = new CreateTableRequest() .withTableName(PropertyLoader.getInstance().getTestTableName()) .withKeySchema(ks) .withProvisionedThroughput(pt);ddb.createTable(request); |
Before we can move to the next step (creating users), we must wait until the status of the tables is ACTIVE. To retrieve the status of the table, we use a describe table request. This request returns information about the table such as the name of the table, item count, creation date and time, and its status.
AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();DescribeTableRequest request = new DescribeTableRequest() .withTableName(PropertyLoader.getInstance().getTestTableName());DescribeTableResult result = ddb.describeTable(request);String status = result.getTable().getTableStatus(); |
For each user, we'll create an item in the table. An item is a collection of attribute/value pairs. For each item, we'll have three attributes: userNo
, firstName
, and lastName
. These are added to a put item request in order to create the item.
HashMap<String, AttributeValue> item = new HashMap<String, AttributeValue>();AttributeValue userNo = new AttributeValue().withN(String.valueOf(i));item.put("userNo", userNo);AttributeValue firstName = new AttributeValue().withS(Constants.getRandomName());item.put("firstName", firstName);AttributeValue lastName = new AttributeValue().withS(Constants.getRandomName());item.put("lastName", lastName);PutItemRequest request = new PutItemRequest().withTableName( PropertyLoader.getInstance().getTestTableName()).withItem(item);ddb.putItem(request); |
To remove a user from the list simply means deleting the corresponding item from the table. We specify the item we wish to delete using the hash key for the item.
AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();Key primaryKey = new Key().withHashKeyElement(targetValue);DeleteItemRequest request = new DeleteItemRequest().withTableName( PropertyLoader.getInstance().getTestTableName()).withKey(primaryKey);ddb.deleteItem(request); |
We can retrieve a collection of users with a scan request. A scan request simply scans the table and returns the results in an undetermined order. Scan is an expensive operation and should be used with care to avoid disrupting your higher priority production traffic on the table. See the Amazon DynamoDB developer guide for more recommendations for safely using the Scan operation.
AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();ScanRequest request = new ScanRequest();request.setTableName(PropertyLoader.getInstance().getTestTableName());ScanResult result = ddb.scan(request);ArrayList<HashMap<String, AttributeValue>> users = (ArrayList<HashMap<String, AttributeValue>>) result.getItems(); |
Knowing a user's userNo
, the hash key of the table, it is easy to find the item for the user. This next snippet shows how to get all the attributes for an item using the hash key.
AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();AttributeValue userNoAttr = new AttributeValue().withN(String.valueOf(userNo));Key primaryKey = new Key().withHashKeyElement(userNoAttr);GetItemRequest request = new GetItemRequest().withTableName( PropertyLoader.getInstance().getTestTableName()).withKey(primaryKey);GetItemResult result = ddb.getItem(request);HashMap<String, AttributeValue> userPreferences = (HashMap<String, AttributeValue>) result.getItem(); |
The hash key also makes it easy to update an attribute for an item.
AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();AttributeValue av = new AttributeValue().withS(value);AttributeValueUpdate avu = new AttributeValueUpdate().withValue(av).withAction(AttributeAction.PUT);Key primaryKey = new Key().withHashKeyElement(targetValue);HashMap<String, AttributeValueUpdate> updates = new HashMap<String, AttributeValueUpdate>();updates.put(key, avu);UpdateItemRequest request = new UpdateItemRequest() .withTableName(PropertyLoader.getInstance().getTestTableName()) .withKey(primaryKey).withAttributeUpdates(updates);ddb.updateItem(request); |
The easiest way to remove all the user preference data is to delete the Amazon DynamoDB table. The following code shows how:
AmazonDynamoDBClient ddb = UserPreferenceDemoActivity.clientManager.ddb();DeleteTableRequest request = new DeleteTableRequest() .withTableName(PropertyLoader.getInstance().getTestTableName());ddb.deleteTable(request); |
The code in this article demonstrates how to use Amazon DynamoDB as a storage device for your mobile application. You can find more information about Amazon DynamoDB here.
Sample apps that include the code from this article are provided with the AWS SDK for Android. You can download the SDK using the following link:
For more information about using AWS credentials with mobile applications see the following article:
Authenticating Users of AWS Mobile Applications with a Token Vending Machine
Please feel free to ask questions or provide comments in the Mobile Development Forum.
At last week’s CES, it was hard to ignore the fact that many technology pundits are considering 2011 as the year of the tablet. And although Apple should be thanked for resurrecting interest in tablets in 2010, 2011 will see a record breaking surge in the number of vendors bringing new tablets to market. Sean Dubravac, Chief Economist and Director of Research, Consumer Electronics Association, predicted, “While many firms are touting product launches within the tablet sphere for the fourth quarter of 2010, the real action will occur a few weeks after the end of the quarter at CES.” The next few weeks will be telling for the future of the tablet and so far it’s looking quite bright.
The good news for you, the Android developer, is that many of these tablets will be sporting Android OS and, with the recent announcement of the Amazon Appstore Developer Portal, you have a convenient way of offering your apps to both tablet and smartphone users. We’re not mandating that you optimize your apps for tablets as well as smartphones, but it’s definitely something you should consider.
The expected surge in the number of tablets on the market and the number of Android devices a single user will own brings forth new opportunities and challenges. The opportunities are clear—more devices mean more users, more hardware features and more APIs to take advantage of. These new tablets will continue to feature larger screens and supported resolution levels, ample amounts of disk space and extremely fast processer speeds that are not far behind that of a typical laptop. An important thing to remember as a developer is that customers may be using your app across tablets and smartphones – no longer just one or the other.
A quick comparison of the best selling smartphones and tablets on Amazon.com shows that tablets boast 50-100% more screen real-estate and 50% more disk space. Furthermore, many of the tablets demonstrated at CES also feature dual-core CPUs. These differences make it more important than ever for developers to be aware of the device capabilities and limitations. With Amazon.com’s convenient 1-Click purchase and digital locker features, customers will be able to buy your apps and run it on any of their Android devices. Unfortunately, the growth in devices will present one of the biggest challenges for you—you want to continue to build and extend your killer apps and offer it to the tens of millions of Amazon.com customers, but you also want to keep your customers happy by setting expectations on how and where the apps can be run.
The Android SDK requires that each application contain a file called AndroidManifest.xml within the apk. This is where you can let the system know what your app needs at a minimum to run and what resources and services it will use. For instance, if you are building a word processor app that is designed to only run on a tablet, you will want to set the android:largeScreens attribute to “true” on the <supports-screens> property, while explicitly setting the small and normal screen flags to false. If you don’t declare this requirement for your app, then the Android system will assume it works on all screen sizes.
On the other hand, if you are building a game that looks great on any phone or tablet, then you can declare this in the xml file by including the following settings:
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true" />
One thing to be aware of, however, is that once you declare support for all screen sizes, you will want to check the DisplayMetrics settings at runtime to make important display decisions in your code. This information can be used to make performance optimizations, such as displaying low to medium resolution images on small devices and high resolution images on large screens—a great way to avoid creating multiple versions of your app.
Apps that depend on hardware resources, such as GPS, Wi-Fi or Bluetooth capabilities, can define these requirements by appropriately setting the <uses-features> option.
Furthermore, with last month’s announcement of the Gingerbread release, there are now 6 flavors of Android OS in use. If the trend over the past two years continues, you can expect one more major release (3.0, Honeycomb) and another minor release to be announced before 2012. With major features being added in every new platform version, such as improved copy-and-paste and faster text input processing in Gingerbread, you will want to take advantage of these capabilities and also ensure your apps only run under their supported environment. The manifest provides a way to enforce dependencies on specific SDK features by using the <uses-sdk> flag.
Customer satisfaction is a key driver behind Amazon.com’s success. As you develop and offer your application to Amazon.com’s customers, following these Android development best practices guidelines is a great start towards achieving similar success.