アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

オフラインの場合の処理をどうすれば良いか

今は高速なネットワークがあるのが当たり前になっており、常時オンラインというのも普通になっています。しかしそれに甘んじて作っていると、ネットワークが使えなくなった途端にアプリが落ちたり、全く動作しなくなってしまったりします。



そのためアプリを作る際には必ずオフラインを意識して作る必要があります。そのために必要なテクニックを紹介します。



オンライン/オフラインをフラグで管理する



Monacaアプリの場合、オンラインになった、またはオフラインになったタイミングで呼ばれるイベントがあります。それを使ってネットワークの状態を管理できます。





// オンラインになった時に呼ばれるイベント
document.addEventListener("online", onOnline, false);

// オフラインになった時に呼ばれるイベント
document.addEventListener("offline", onOffline, false);


この二つを使ってフラグを管理します。





var online = false;
var onOnline = function () {
    console.log("I'm online");
    online = true;
}
var onOffline = function () {
    console.log("I'm offline");
    online = false;
}
document.addEventListener("online", onOnline, false);
document.addEventListener("offline", onOffline, false);


そして、例えばこんな感じにネットワーク状態を出力するようにしてみます。onOnline/onOfflineでDOM操作を行っていないのはonlineのフラグの状態変更と画面の変更とを疎結合のしたいからです。





setInterval(function () {
    document.getElementById("status").innerText = online ? "オンライン" : "オフライン";
}, 1000);


そうするとネットワークの有無によって表示が変わるのが確認できるかと思います。



アプリ開発時のコツ



そしてこのフラグを使う場合は、タップイベントなどでそのままデータを外部にPOSTするのではなく、一旦処理を吸収してくれるラッパーを使うのがお勧めです。このラッパーはオンラインであればデータをPOSTし、オフラインであればキューに入れておきます。そしてネットワークが復旧したタイミングで溜まっているキューを処理します。



そうすることでUI側でのイベントと外部サービスが疎結合になり、メンテナンスしやすいコードになるでしょう。データの保存時はもちろん、データの取得時においても同様の処理にしておくことで、例えばオフライン時には単なる配列を返すようにするといった工夫も考えられます。



例えば以下のようなコードが考えられます。これはそのままでは動作しません。あくまでもサンプルになりますのでご注意ください。





var online = false;

/*
  追加ボタンをクリックした時の処理
*/
$(".add").on("click", function () {
  obj.post(data);  // DOM側では特に区別なし 
});

/*
  オンライン、オフラインをラッピングしてくれるオブジェクト
*/
var obj = {
  /*
    データの追加処理。
	オフラインの場合は処理せずキューに追加
  */
  post: function (data) {
    if (online) {
	  // データ投稿処理
    } else {
	  // キューに追加しておく
      this.queues.push({
        type: 'post',
	    data: data
	  });
	}
  },
  
  /*
    キューを処理するメソッド
  */
  exec: function() {
    var me = this;
	if (!online) return false; // オフラインなら何もしない
	$.each(this.queues, function(i, queue) {
	  if (queue.type == 'post') {
	    me.post(queue.data);
		// 処理が成功したらキューを消すといった処理が必要
	  }
	  : // その他の処理
    });
  }
}

var onOnline = function () {
  if (online) return false; // 既にオンラインだったら何もしない
  obj.exec(); // キューがあれば実行
}
document.addEventListener("online", onOnline, false);


この場合、保存したはずのデータが保存されていなかったと言った事態は防げるでしょう。さらに取得したデータをオフライン利用時用にIndexedDBやlocalStorageに保存したり、キャッシュするような工夫が必要になってくるかと思います。






Webアプリケーションの場合、あまりオフラインを気にすることはないかと思います。そもそもオフライン時にはアクセスできなくなります。しかしアプリの場合、アプリ内部にコンテンツがありますのでオフライン時でもある程度使える必要があります。まずはオンラインまたはオフラインを感知して、それによって処理分けするというのがお勧めです。