読者です 読者をやめる 読者になる 読者になる

TitaniumMobile勉強記

Web系エンジニア向けのキャリアアドバイザーやってましたが現在はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連(Node.js、Titanium)あたり

045-MVCのControllerの役割を見直すその4

まず現在のJSONフォーマット

以前書いたエントリでは投稿した日付をIDとして活用すればいいかなぁと考えていたものの、何となく処理をやりづらそうな何とも言えないモヤモヤ感がしてました。

twitterAPIで返すJSON形式を眺めていたら、下記のような形式が良いのかと思ってこれでいくことにしました。

[
  {
    "permalink":"http://blog.pasonatech.co.jp/hibi/299/1814.html",
    "title":"IT\u7cfb\u30d9\u30f3\u30c1\u30e3\u30fc\uff0b\u30de\u30de\uff0bSOHO\uff1a\u521d\u30a8\u30f3\u30c8\u30ea\u30fc",
    "html_body":"<p>省略</p>",
    "_id":"4d99001ce93ac16b6c000001",
    "post_date":"2006-08-10T14:09:00Z",
    "blogger":"hibi"
  },
  {
    // 以下続く
  }
]

SQLite使ってDBに保存するようにローカルのキャッシュ処理も見直し

JSON形式でサーバから受け取ったら、TitaniumのResources/cacheというディレクトリ準備してそこにテキスト形式で保存。必要に応じてそこから読み込みという感じでキャッシュ処理を考えていました。

そうなると

var last_entry=[
              {"//省略},
              {//省略}
            ];
var local_cache=[
              {"//省略},
              {//省略}
            ];
var entries = this.merge(last_entry,local_cache);

のような処理をどっかで組み込まないといけないと思ったのですが、自分のスキルではこれが思いつかなかったので、SQLite使ってDBに保存するようにローカルのキャッシュ処理も見直しすることにしました。

実装にあたって

Controllerに処理が集中してきたので、責任範囲を分担することにしました。

具体的には、Cacheクラスを作って、そこでローカルのキャッシュの保存、キャッシュの有無の判別、キャッシュ全件読み込み・・・という感じにしようかと思ってます

// cache.js
var Cache = function(){
  this.dbName = "entry";
  this.db = null;
};
Cache.prototype = {
  open:function(){
    this.db = Titanium.Database.open(this.dbName);
    return true;
  },
  close :function () {
    this.db.close();
    this.db = null;
  },
  save:function(entries) {
    this.open();
    this.db.execute('CREATE TABLE IF NOT EXISTS entries(blogger TEXT, permalink TEXT, title TEXT, html_body TEXT, post_date DATE)');
    for (var i=0;i<entries.length;i++) {
      var entry = entries[i];
      var rows = this.db.execute(
        'SELECT * FROM entries WHERE post_date = ?',
        entry.post_date
      );
      Titanium.API.info('Found: ' + rows.getRowCount() );
      if ( rows.getRowCount() > 0 ) continue;
      var res = this.db.execute(
        'INSERT INTO entries (blogger,permalink,title,html_body,post_date) VALUES(?,?,?,?,?)',
        entry.blogger,
        entry.permalink,
        entry.title,
        entry.html_body,
        entry.post_date
      );
      Titanium.API.info('Add to DB');
    }
    this.close();
    return true;
  },
  find:function(post_date){
    var flag = null;
    this.open();
    var count = this.db.execute(
      'SELECT count(*) FROM entries WHERE post_date = ?',
      post_date
    );
    if(count===0){
      flag = false;
    }else{
      flag = true;
    }
    this.close();
    return flag;
  }
};

上記キャッシュ利用するようにControllerも見直し。

Titanium.include(Titanium.App.appURLToPath("app://model/entry.js"));
Titanium.include(Titanium.App.appURLToPath("app://model/cache.js"));
Titanium.include(Titanium.App.appURLToPath("app://view/styles.js"));
Titanium.include(Titanium.App.appURLToPath("app://view/create_table_view.js"));


Controller = function(blogger){
  this.blogger = blogger;
  this.page_number = 1; // スタートページとして初期値で1を設定
  this.entry_cache = [];
};

Controller.prototype = {
  init:function(){
    if(this.page_number===1){
      this.entry = new Entry(this.blogger);
      this.entry.getEntry(this.page_number);
    }
    return true;
  },
  getCurrentPage:function(){
    return this.page_number;
  },
  nextPage:function(){
    this.page_number++;
    return this.page_number;
  },
  receive:function(json,current_page){
    Titanium.API.info('current_page' + current_page);
    var _json = eval(json);
    this.page_number = current_page;
    this.nextPage();
    if(current_page===1){
      this.saveCache(_json);
    }else{
      this.saveCache(_json);
    }
    var tv = new CreateTableView();
    var entries = tv.makeRow(_json);
    tv.setData(entries,current_page);

  },
  tableViewSetData:function(data){
    var tv = new CreateTableView();
    return tv.setData(data);
  },
  saveCache:function(json){
    var cache = new Cache();
    cache.save(json);
    return true;

  },
  loadCache:function(blogger){
    var fileName = blogger + ".json";
    var file_path = Titanium.Filesystem.resourcesDirectory
    	+ '/cache/'
    	+ fileName;
    var file = Titanium.Filesystem.getFile(file_path);
    var result = file.read();
    return result;

  },
  handleCache:function(){
    var array = [];
    array.push(json);
    var cache = this.union(this.loadCache(),array);
    this.sessinObject(cache);

  },
  sessinObject:function(cache){
    //アプリケーション実行中は
    //Titanium.App.ブロガー名前で参照できるようにする
    var self = this;
    var _blogger = self.blogger;
    Titanium.App.self[_blogger]= cache;

    return Titanium.App.self[_blogger];
  }

};
var blogger_name = 'hibi';
var c = new Controller(blogger_name);
c.init();

実行した後、SQLite上に保存されているかどうかターミナル上で確認出来たので、最低限の処理は今のところ出来たと思います

$ cd ~/Library/Application Support/iPhone Simulator/4.2/Applications/YOURPROJECTNAME/Library/Application Support/database
$ sqlite3 entry.sql
sqlite> select post_date from entries where post_date > '2006-08-24';
2006-08-24T01:25:00Z
2006-08-24T20:21:00Z
2006-08-26T15:14:00Z
2006-08-29T13:22:00Z
2006-09-04T13:52:00Z
2006-09-06T01:21:00Z
2006-09-11T18:49:00Z
2006-09-14T16:30:00Z
2006-09-18T18:21:00Z