Backup / Restore

Data Backup – Part 1

Normally on Styling Android I try and stick to UI / UX tips and techniques, but in this series of articles I’m going to cover a topic that is not directly UI / UX specific yet, if implemented, can delight your users: using Android Data Backup to backup and restore app settings / config to the cloud. The technique that we’re going to explore is something that I implemented a while ago in an app that I created just for my own use, but whenever I switch devices, I’m always pleasantly surprised when my config magically reappears on the new device, and I don’t need to configure my app from scratch. Data backup is something that Google Developer Advocate Richard Hyndman has recently blogged about demonstrating how app settings can be manually backed up and restored on ICS. I can only agree with Richard’s sentiment that it is a pity that more games do not implement cloud backup to store your progress. In this series of articles we’ll look at how easy it is to implement cloud backup in your app using the built in Data Backup tools.

Before we go any further, it is worth a quick explanation of how Android Data Backup actually works. Although the framework supports different backup providers, I’m going to stick with the default backup service provided by Google because it just works straight out of the box. In order to use this service the device must be registered to the user’s Google account, and all data will be stored against that account. If the user switches devices and re-installs your app all data backed up by your app will be restored when the app is installed provided that the user has registered the new device to the same Google account. It really is very simple and I guarantee that the first time you see it working you will surprise yourself!

Data Backup is supported from Android 2.2 (API Level 8 / Froyo) onwards. If you want to target earlier versions of Android with your app, I would still suggest using this technique, but use reflection to determine whether Data Backup is supported, and simply disable it at runtime on Android versions which don’t support it.

It is worth a quick discussion of how Data Backup should be used. According to the Google documentation, it is not designed to synchronise data across multiple clients, but more a mechanism to migrate your data to new devices. In other words you should use it sparingly: Don’t store large amounts of data in the cloud, and don’t flood the cloud service with either backup or restore requests. There are mechanisms built in to prevent lots of backup requests, but it is possible to force restores, so care needs to be taken here.

OK, enough of the background information, let’s have create a simple app which contains an EditText which persists its value to SharedPreferences so that the value persists across different invocations of the app. Let’s create a 4.0.3 app named BackupRestore with a package name of com.stylingandroid.backuprestore, and a default Activity named BackupResoreActivity:

[java] public class BackupRestoreActivity extends Activity implements
OnSharedPreferenceChangeListener
{
public static final String PREFS = “prefs”;
public static final String KEY = “key”;

private EditText edit;
private BackupManager backupMgr = null;

private SharedPreferences sharedPrefs;

@Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
setContentView( R.layout.main );

sharedPrefs = getSharedPreferences(
BackupRestoreActivity.PREFS,
MODE_PRIVATE );

edit = (EditText) findViewById( R.id.editText );
edit.addTextChangedListener( new TextWatcher()
{
private int start = 0;
private int end = 0;

@Override
public void onTextChanged(
CharSequence s, int start,
int before, int count )
{
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString(
BackupRestoreActivity.KEY,
s.toString() );
editor.commit();
}

@Override
public void beforeTextChanged(
CharSequence s, int start,
int count, int after )
{
this.start = after;
this.end = after;
}

@Override
public void afterTextChanged( Editable s )
{
edit.setSelection( start, end );
}
} );

backupMgr = new BackupManager( getApplicationContext() );
}

@Override
protected void onResume()
{
sharedPrefs.registerOnSharedPreferenceChangeListener( this );
String val = sharedPrefs.getString( KEY, null );
if ( val != null )
{
edit.setText( val );
}
super.onResume();
}

@Override
protected void onPause()
{
sharedPrefs.unregisterOnSharedPreferenceChangeListener( this );
super.onPause();
}

@Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences,
String key )
{
if ( key.equals( KEY ) )
{
String newVal = sharedPreferences.getString( key, null );
if ( newVal != null )
{
edit.setText( newVal );
}
}
}
}
[/java]

Hopefully this should be fairly straightforward. In onCreate we get our EditText control and add a TextChangeListener to it so that we detect changes to the text and we store changes to the SharedPreferences as they occur. We also get a new BackupManager instance which we’ll discuss further as we progress.

In onResume and onPause we register and unregister an OnSharePreferneceChangeListener so that we can detect changes made to SharedPreferences when a restore occurs. We handle this in onSharedPreferenceChanged and simply set the value of our EditText control to whatever is the new SharedPreferences value is.

It is worth noting that we have defined a couple of constants which we’ll use later.

There’s also the layout file in res/layout/main.xml:

[xml]


6 Comments

  1. This might not be UI related, but UX it nevertheless is.

    As a user I profit by my data being transfered. And it makes switching devices much easier for all that stuff that is not already up in the cloud. So any app having a feature like this is more usable after a device change than any not having it.

    Now it’s up to us developers to listen to you and follow your blog posts 🙂

  2. Backup Agent is insecure. Your backup key is … Everyone can obtain this key by using your package name. So it can use it to retrieve its own data with another application. That is not critical because you can obtain only data attached to your account; but that’s a fail.
    Otherwise, in your example, your data is saved locally and not saved in the cloud. You need to wait one hour for a network backup. And if you change phone, nothing comes…
    Seriously it is a joke for game developper.

    1. You’re right that the key is insecure, but only the app with the correct package name declared in the Manifest can use that key. So unless you have my signing certificate (which I’m pretty sure you don’t) you cannot put an app in the Market which uses my backup key.

      I do actually mention in the article that the backup to the cloud does not occur immediately.

      Also, data *does* come back if you change phones. I change devices regularly and, provided I activate each device using the same Google ID, the data comes back every time.

  3. Hello,

    Thanks for your reply, i use your code with my own package name (and my key) without success. I have publish my app called com.iopixeltest.backupsuccess. The backup seems ok (adb bugreport) but when i reset my phone, nothing is restored. My app isn’t reinstalled by google too. I didn’t understand the problem [I have waited a night]

    Thanks for your help,

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.