連載
» 2013年07月18日 18時00分 公開

あなたのアプリはクラウドにデータをバックアップできますか?Androidで動く携帯Javaアプリ作成入門(44)(3/3 ページ)

[緒方聡,イーフロー]
前のページへ 1|2|3       

バックアップエージェントの実装(BackupAgent編)

 「BackupAgentHelper」クラスを継承したバックアップエージェントは、ほとんどonCreate()だけで実装が済んでしまいましたが、「BackupAgent」クラスを継承するバックアップエージェントは少し複雑です。ただし、細かな制御も可能になります。

 実装が少し長いので、onCreate()から見ていきましょう。

    @Override
    public void onCreate() {
        mDataFile = new File(getFilesDir(), FILENAME);
    }

 ファイルディレクトリに保存されているデータファイルを作成します。後で、このファイルから内容を読み出してバックアップデータを生成します。

 次はonBackup()です。

    @Override
    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
            ParcelFileDescriptor newState) throws IOException {
        Log.d(TAG, "Backup...");
        synchronized (LOCK) { // 【1】
            RandomAccessFile file = new RandomAccessFile(mDataFile, "r");
            mCount = file.readInt(); // 【2】
            file.close();
        }
        boolean doBackup = (oldState == null); // 【3】
        if (!doBackup) {
            doBackup = compareStateFile(oldState); // 【4】
        }
        if (doBackup) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(baos);
            dos.writeInt(mCount);
            byte[] buffer = baos.toByteArray();
            int len = buffer.length;
            data.writeEntityHeader(APP_DATA_KEY, len); // 【5】
            data.writeEntityData(buffer, len);
        }
        writeStateFile(newState); // 【6】
    }

 ファイル内容を読み出す場合も、【1】のようにsynchronizedで排他するのは同様です。

 【2】では、ファイルからデータを取り出しています。FileBackupHelperを用いる実装と異なるのはバックアップ対象データを扱う柔軟さですが、実装が複雑になる部分でもあります。

 【3】では、バックアップを取る必要があるかどうかを判断しています。oldStateがnullならバックアップが必要、または【4】でバックアップ実装またはデータ内容が異なる場合はバックアップが必要、と判断しています。

 バックアップが必要な場合、【5】でバックアップデータを書き出しています。【6】では、現在の状態をnewStateに書き出します。

 最後にonRestore()です。

    @Override
    public void onRestore(BackupDataInput data, int appVersionCode, // 【1】
            ParcelFileDescriptor newState) throws IOException {
        Log.d(TAG, "Restore...");
        while (data.readNextHeader()) { // 【2】
            String key = data.getKey();
            int dataSize = data.getDataSize();
            if (APP_DATA_KEY.equals(key)) { // 【3】
                byte[] dataBuf = new byte[dataSize];
                data.readEntityData(dataBuf, 0, dataSize);
                ByteArrayInputStream bais = new ByteArrayInputStream(dataBuf);
                DataInputStream din = new DataInputStream(bais);
                mCount = din.readInt(); // 【4】
                MainActivity.sendBroadcast(this, mCount); // 【5】
                synchronized (LOCK) { // 【6】
                    RandomAccessFile file = new RandomAccessFile(mDataFile,
                            "rw");
                    file.setLength(0L);
                    file.writeInt(mCount);
                    file.close();
                }
            } else {
                data.skipEntityData(); // 【7】
            }
        }
        writeStateFile(newState); // 【8】
    }

 今回の実装では使いませんでしたが、【1】のようなappVersionCodeでアプリのバージョンコードが渡されてきます。バージョンコードはバックアップの際には自動的に収集されます。

 今回はバックアップエージェントにバージョンを独自に持ちましたが、アプリのバージョンコードで実装の違いを管理するのも1つの方法です。

 バックアップされたデータには複数の領域が存在する可能性があるため、データを読み出す際には、【2】のようにwhileループですべてのヘッダを読み出して目的のデータを探し出す必要があります。

 目的のデータかどうかは【3】のように確認します。データ形式が分かっているので【4】のようにデータを直接読み出します。

 【5】では、Intentをブロードキャストしてデータを画面に即時反映しています。繰り返しになりますが、ファイルの読み書きは【6】のような排他が必要です。

 目的のデータではなかった場合、【7】のようにスキップします。これは通常は起こりませんが、古いアプリが新しいバックアップデータを読んでしまうようなケースに限られるでしょう。

 【8】のように現在の状態をnewStateに書き出してレストアは終了です。

データバックアップ時の4つの注意点

 アプリのデータバックアップ、いかがだったでしょうか。買い替えなどで新しい端末にアプリを再インストールしたとき、以前の状態が復元されると、ユーザーの利便性が増し、「おおっ」とか「ちゃんとしてるな」という印象を得られるのではないでしょうか。

 最後になりますが、バックアップで注意すべき点を個条書きにして今回は終わりにします。

  1. バックアップをデータ同期の目的で使用しない
  2. バックアップ対象のデータが変更されたらdataChanged()を呼び出すべき
  3. バックアップはいつ実施されるか分からないため、過度に信頼しない
  4. requestRestore()はユーザーデータが失われる可能性があるので、使う際は注意
「Androidで動く携帯Javaアプリ作成入門」バックナンバー
前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

編集部からのお知らせ

6月16日にフォーマット統一のため利用規約を変更します

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。