2010-11-07

「Back」ボタンの実装 - セッション管理 (Blogger Glass)

iPhone アプリらしい外観には「Back」ボタンが必要だ。Safari の「戻る」ボタンを使ったのではアプリらしくない。そして「Back」ボタンを実装するためには画面の履歴を記録しておくための仕組みが必要だ。

履歴を記録する仕組みは大きく 2 つの部分に分かれる。履歴そのものを(文字列のリストとして)記録しておくための部分と、そのリストをクライアント(ブラウザ)ごとに持つための部分だ。前者の実装は「リングバッファを作る」で説明した。また、後者を実現するためのセッション管理の肝となる部分も「Cookie の使い方」で説明ずみだ。

今回は、これまでに実装した「かけら」を Blogger Glass に組み込みセッション管理を実現するとともに、セッションデータとして履歴を保持させることで、「Back」ボタンを実現する。

セッション管理

session モジュールに定義した Session クラスは Cookie を用いたセッション管理を実現する。また、セッション固有のデータを data 属性として保持している。このセッション固有データは GAE のデータストアサービスで保存される。

セッションの作り方(ID の生成、ブラウザとの Cookie の授受)は「Cookie の使い方」に書いたコードをほぼそのまま流用している。

セッション管理のほとんどは Session オブジェクトの初期化時に完了している。この初期化時には、リクエストハンドラから RequestResponse のオブジェクトがわたってくることを想定しており、ブラウザとの Cookie の授受も、この 2 つのオブジェクトを通して行っている。

セッション管理の利用者(リクエストハンドラ)側では、Session オブジェクトを初期化し、セッション固有データとしての data 属性を読み書きするだけで良い。

セッション固有のデータ

現在のところ、セッション固有データとして保持するのはリクエスト履歴のみで、これは URL (文字列)のリストになるため、データストア用のモデルは以下のようになる。

(src/model.py より)
class SessionData(db.Model):
    history = db.StringListProperty()

セッション管理をリクエストハンドラに組み込む

Session クラスを使ってセッション管理(とセッション固有データの保存)には以下のようなコードを書く。この関数自体は util モジュールで定義している。

(src/util.py より)
def save_url(request, response):
    history = RequestHistory()
    sess = session.Session(request, response)
    history.import_history(sess.data.history)
    logging.info("Hisotry: %s" % history)
    history.push(request.uri)
    sess.data.history = history.export_history()
    sess.data.put()

リクエストハンドラの get メソッド等で以下のような関数を呼び出す。

back リクエストの追加

セッション固有データとして保存された履歴をたどって、前の画面に戻る動作を実現するのは back リクエストを受けるハンドラになる。

back リクエストの基本的な処理は、(セッション固有データから)リクエスト履歴を 2 つ読み取り、2 つ目のリクエスト URL にリダイレクトする、というものだ。履歴の 1 つ目は back リクエストを送ってきた画面(つまり「Back」ボタンが配置されている画面)であり、戻るのはそのさらに 1 つ前(履歴の 2 つ目)のリクエスト URL になる。ただし、画面によってはユーザ体験として戻る意味のない画面もあり(例: メニュー画面)、そこはスキップし、さらに前の画面に戻るようにしてある。また、戻るべき履歴が空の場合は、いつもトップ画面に戻る。

セッション固有データからの履歴の読み取りは util モジュールで定義した以下の関数で行う。

(src/util.py より)
def load_url(request, response):
    sess = session.Session(request, response)
    history = RequestHistory()
    history.import_history(sess.data.history)
    from_url = history.pop()
    back_url = history.pop()
    if not back_url:
        back_url = '/'
    sess.data.history = history.export_history()
    sess.data.put()
    return (from_url, back_url)

その他の変更点

以下のコミットを参照。

次の一手

「Back」ボタンが完成したので、「iPhone アプリらしく #2 - 実装 (Blogger Glass)」で(画面には配置しておきながら)未実装のままにしておいた部品のうち、残っているのは「Labels」となる。これは、「ポスト画面」で表示中の記事に付けられたラベル一覧を表示する画面に移るためのものだ。

これを実現するには、「Back」ボタンと同様にセッション固有のデータに保存しても良いし(保存先は memcache で十分か)、ブログ ID とポスト ID をキーとしてグローバルデータとして保存するのでも良い。とりあえず、セッション固有データとして保存する方式で作ってみようか。

関連リンク

関連記事

0 件のコメント:

コメントを投稿