MOBILE

Building Android Apps: Web Storage

1/2/2011 3:17:55 PM
Most software applications need to store data in some sort of persistent fashion in order to be useful. When it comes to web apps, this task has traditionally been handled with either a server-side database or cookies set in the browser. With the advent of HTML5, web developers now have a couple more options: Web Storage, and Web SQL Database.

1. Web Storage

Web Storage comes in two flavors—localStorage and sessionStorage—and are very similar to cookies in that they allow you to use JavaScript to set name/value pairs that you can retrieve across multiple page reloads.

Unlike cookies, however, Web Storage data is not sent across the wire with the browser request—it lives entirely in the client. Therefore, it’s feasible to store much more data than you would want to with cookies.


Note:

At the time of this writing, browser size limits for Web Storage are still in flux. However, my most recent tests indicate that the limit is right around 2.5 MB.


Functionally, localStorage and sessionStorage are the same. They differ only in terms of persistence and scope:


localStorage

Data is saved even after the window is closed and is available to all windows (or tabs) that are loaded from the same source (must be the same domain name, protocol, and port). This is useful for things like application preferences.


sessionStorage

Data is stored with the window object. Other windows/tabs are not aware of the values, and the data is discarded when the window/tab is closed. Useful for window-specific state like active tab highlight or the sort order of a table.


Note:

In any of the following examples, you can substitute sessionStorage anywhere you see localStorage, but remember that sessionStorage goes away when you close the window or tab.


Setting a value is as simple as the following:

localStorage.setItem('age', 40);

Accessing a stored value is equally simple:

var age = localStorage.getItem('age');

You can delete a specific key/value pair from storage like so:

localStorage.removeItem('age');

Or, you can delete all key/value pairs like so:

localStorage.clear();

Assuming your keys are valid JavaScript tokens (e.g., no spaces, no punctuation other than underscores) you can use this alternate syntax:

localStorage.age = 40 // Set the value of age
var age = localStorage.age; // Get the value of age
delete localStorage.age; // Remove age from storage


Note:

The localStorage and sessionStorage keys are stored separately. If you use the same key name for each, they will not conflict with each other.


1. Saving User Settings to Local Storage

We are going to be writing a fair amount of JavaScript in this article, and I don’t want to jam it all in the head section of our HTML document. To keep our code organized, create a file called kilo.js in the same directory as your HTML document, and update the head of your HTML document with a reference to kilo.js:

<head>
<title>Kilo</title>
<link type="text/css" rel="stylesheet" media="screen"
href="jqtouch/jqtouch.css">
<link type="text/css" rel="stylesheet" media="screen"
href="themes/jqt/theme.css">
<script type="text/javascript" src="jqtouch/jquery.js"></script>
<script type="text/javascript" src="jqtouch/jqtouch.js"></script>
<script type="text/javascript" src="kilo.js"></script>
</head>

Alert readers will notice that I’ve also removed the jQTouch constructor from the head of the HTML document. It’s not gone, though; I just moved it into kilo.js. Be sure you remove that from your main HTML file and create the kilo.js file in the same directory with the following contents, then reload the main HTML document in your browser to make sure it’s still working:

var jQT = $.jQTouch({
icon: 'kilo.png'
});

With that little bit of code reorganization out of the way, it’s time to add the code needed to save the settings. You need to override the submit action of the Settings form and replace it with a custom function called saveSettings(). Thanks to jQuery, you can accomplish this with a single line of code, which you must place in the document ready function. Add the following to kilo.js:

$(document).ready(function(){
$('#settings form').submit(saveSettings);
});

The net result of this is that when the user submits the settings form, the saveSettings() function will run instead of the form actually getting submitted.

When the saveSettings() function is called, it grabs the values from the three form inputs using jQuery’s val() function and saves each in a localStorage variable of the same name. Add this function to kilo.js:

function saveSettings() {
localStorage.age = $('#age').val();
localStorage.budget = $('#budget').val();
localStorage.weight = $('#weight').val();
jQT.goBack();
return false;
}

Once the values are stored, use the jQuery goBack() function (on the second-to-last line) to dismiss the panel and return to the previous page. Next, return false to prevent the default action of the submit event that triggers this function. Had we omitted this line, the current page would reload, which is not what we want.

At this point, a user can launch the app, navigate to the Settings panel, enter her settings, and submit the form to save the settings to localStorage.

Since we are not clearing the fields when the form is submitted, the values that the user enters will still be there when she navigates back to the Settings panel. However, this is not because the values have been saved to localStorage; it’s because they are still sitting there after having been typed in.

Therefore, the next time the user launches that app and navigates to the Settings panel, the fields will be empty, even though they have been saved.

To remedy this, we need to load the settings using the loadSettings() function, so add the following function to kilo.js:

function loadSettings() {
$('#age').val(localStorage.age);
$('#budget').val(localStorage.budget);
$('#weight').val(localStorage.weight);
}

The loadSettings() function is the opposite of the saveSettings() function; it uses jQuery’s val() function to set the three fields of the Settings form to the corresponding values saved in localStorage.

Now that we have a loadSettings() function, we need to trigger it. The most obvious time to do this is when the app launches. To make this happen, simply add a line to the document ready function in kilo.js:

$(document).ready(function(){
$('#settings form').submit(saveSettings);
loadSettings();
});

Unfortunately, loading the settings only at startup leaves a loophole that occurs if the user navigates to the Settings panel, changes some values, and taps the Cancel button without submitting the form.

In this case, the newly changed values will still be sitting there the next time the user visits the Settings panel; not because the values were saved (they weren’t), but because they are still just sitting there. If the user closes and reopens the app, the displayed values will revert to the saved values because the loadSettings() function will refresh them at startup.

There are several ways to rectify this situation, but I think the most appropriate is to refresh the displayed values whenever the Settings panel begins to move, either into or out of view.

Thanks to jQTouch, this is a simple matter of binding the loadSettings() function to the pageAnimationStart event of the Settings panel. Replace the line you just added with the code shown in bold:

$(document).ready(function(){
$('#settings form').submit(saveSettings);
$('#settings').bind('pageAnimationStart', loadSettings);
});

The JavaScript contained in the kilo.js file now provides persistent data support for the Settings panel. When you view the code we’ve written to make this happen, there’s really not much to it. Here is everything in kilo.js so far:

var jQT = $.jQTouch({
icon: 'kilo.png'
});
$(document).ready(function(){
$('#settings form').submit(saveSettings);
$('#settings').bind('pageAnimationStart', loadSettings);
});
function loadSettings() {
$('#age').val(localStorage.age);
$('#budget').val(localStorage.budget);
$('#weight').val(localStorage.weight);
}
function saveSettings() {
localStorage.age = $('#age').val();
localStorage.budget = $('#budget').val();
localStorage.weight = $('#weight').val();
jQT.goBack();
return false;
}

2. Saving the Selected Date to Session Storage

Ultimately, what we want to do is set up the Date panel so that when it’s displayed, it will check the database for any records entered for that date and display them as an edge-to-edge list. This requires that the Date panel know which date the user tapped on the Dates panel.

We also want to allow the user to add and delete entries from the database, so we’ll have to add support for the + button that already exists on the Date panel, and for the Delete button in the Date panel entry template (more on this later).

The first step is to let the Date panel know which item the user clicked when she navigated to it from the Dates panel. With this piece of information, you can calculate the appropriate date context. To do so, you need to add some lines to the document ready function in kilo.js:

$(document).ready(function(){
$('#settings form').submit(saveSettings);
$('#settings').bind('pageAnimationStart', loadSettings);
$('#dates li a').click(function(){
var dayOffset = this.id;
var date = new Date();
date.setDate(date.getDate() - dayOffset);
sessionStorage.currentDate = date.getMonth() + 1 + '/' +
date.getDate() + '/' +
date.getFullYear();
refreshEntries();
});
});

function refreshEntries() {
var currentDate = sessionStorage.currentDate;
$('#date h1').text(currentDate);
}

Next, we’ll move on to a more powerful and complex client-side data storage method that we’ll use to store the user’s food entries on the Date panel.

Other  
  •  Building Android Apps : Simple Bells and Whistles
  •  Building Android Apps : Traffic Cop
  •  iPhone Application Development : Exploring Interface Builder - Connecting to Code
  •  iPhone Application Development : Customizing Interface Appearance
  •  iPhone Application Development : Creating User Interfaces
  •  iPhone Application Development : Understanding Interface Builder
  •  Android Security Tools
  •  Android Security : Binder Interfaces
  •  Android Security : Files and Preferences
  •  Android Security : ContentProviders
  •  Android Security : Services
  •  Android Security : Broadcasts
  •  Android Security : Activities
  •  Android Security : Creating New Manifest Permissions
  •  Android Permissions Review
  •  Android’s Security Model
  •  Android’s Securable IPC Mechanisms
  •  CSS for Mobile Browsers : CSS Techniques
  •  CSS for Mobile Browsers : Selectors
  •  CSS for Mobile Browsers : Where to Insert the CSS
  •  
    Video
    Top 10
    AMD Radeon HD 7970 - The World's Fastest Single-GPU (Part 3)
    AMD Radeon HD 7970 - The World's Fastest Single-GPU (Part 2)
    AMD Radeon HD 7970 - The World's Fastest Single-GPU (Part 1)
    Intel Core I7 3820 (Part 2)
    Intel Core I7 3820 (Part 1)
    Upgrade Website With Mysql On Linux (Part 2) - Access MySQL from Perl
    Upgrade Website With Mysql On Linux (Part 1) - Access MySQL from PHP
    Where Is My Hard Drive Capacity? (Part 2) - Beat the browser
    Where Is My Hard Drive Capacity? (Part 1) - ITunes culprit
    Viewsonic V3D231
    Most View
    Managing and Administering SharePoint 2010 Infrastructure : Using Additional Administration Tools for SharePoint
    Binding Application Data to the UI objects in Silverlight
    iPhone Application Development : Getting the User’s Attention - Generating Alerts
    Understanding and Using Windows Server 2008 R2 UNIX Integration Components (part 2)
    iPhone Application Development : Creating and Managing Image Animations and Sliders (part 3) - Finishing the Interface
    Cisco Linksys X3000 - The Link to Connectivity
    HP LaserJet Pro CM1415fnw - Print from The Clouds
    Building Your First Windows Phone 7 Application (part 2) - Using Your First Windows Phone Silverlight Controls
    Determine Your Need for Server Core
    Mobile Application Security : Bluetooth Security - Overview of the Technology
    Using System Support Tools in Vista
    Windows 7 : Using Windows Live Calendar (part 3) - Scheduling Appointments and Meetings & Viewing Agendas and Creating To-Do Lists
    Advanced ASP.NET : The Entity Framework (part 3) - Handling Errors & Navigating Relationships
    Graham Barlow: the Apple view
    Ipad : Presentations with Keynote - Adding Transitions (part 2) - Object Transitions
    Windows Server 2003 : Troubleshooting Group Policy
    Microsoft XNA Game Studio 3.0 : Controlling Color (part 2)
    Building the WinPE Image
    Programming the Mobile Web : HTML 5 (part 3) - Offline Operation
    Windows Phone 7 Development : Using Culture Settings with ToString to Display Dates, Times, and Text