Titanium Mobileで作る! iPhone/Androidアプリ

第10回 データベースの使用

この記事を読むのに必要な時間:およそ 5 分

データベースを使ってみる

前回の記事ではTitanium.App.Propertiesやファイル入出力を利用したデータの永続化について解説しましたが,今回はRDBMSを利用したデータの扱い方について解説します。具体的には,自分のホーム画面のタイムラインを取得保存し,前回起動時に取得した分のタイムラインも閲覧できたり,タイムラインの内容を検索できるようにしてみます。

タイムラインの取得

この実装のために今までのサンプルコードを一部改変します。最初の画面で自分の発言だけでなく,フォローしている人も含めたタイムラインが閲覧できるようにtable_view.jsのタイムライン取得部分に次のような変更を加えています。

Ti.include("lib/twitter_api.js");
Ti.include("twitter_settings.js");
Ti.include("tweet_db.js");
//initialization
Ti.App.twitterApi = new TwitterApi({
    consumerKey: TwitterSettings.consumerKey,
    consumerSecret: TwitterSettings.consumerSecret
});
var twitterApi = Ti.App.twitterApi;
twitterApi.init(); 

twitterApi.statuses_home_timeline(
    {
        onSuccess: function(response){
            updateTimeline(db.savedTweets());
        },
        onError: function(error){
            Ti.API.error(error);
        }
    }
);

今まではmessage_window.jsのほうにあったTwitterApiオブジェクトの初期化をtable_view.jsに移動しています。また,タイムラインの取得をTwitterApiオブジェクトを通して実行するようにしています。

自分のタイムラインが表示されるようになりました

自分のタイムラインが表示されるようになりました

Titanium.Database

さて,TitaniumにはTitanium.Databaseというオブジェクトを通してRDBMSにアクセスする機能が実装されており,iPhoneにもAndroidにもライブラリが搭載されているSQLiteを利用することができます。SQLiteはパブリックドメインのRDBMSで,軽量かつ高速に動作することから様々な分野でよく利用されているRDBMSです。MySQLなどほかのRDBMSに慣れている方であればそれほど苦なく扱うことができると思います。

では今回は,データベースに接続するためのオブジェクトをまず先に作ってしまいましょう。全く新しいファイルtweet_db.jsをResourcesディレクトリに作成し,次のコードを実装します。このオブジェクトを利用するときは関数TweetDBをnewして利用します。

var TweetDB = function() {
    this.dbName = 'tweetdb'; //(1)
    
    this.open = function () { //(2)
        this.db = Titanium.Database.open(this.dbName);
    };

    this.close = function () { //(3)
        this.db.close();
    };

    this.addTweets = function (tweets) { //(4)
        this.open();
        for (var i=0;i<tweets.length;i++) {
            var tweet = tweets[i];
            var rows = this.db.execute( //(5)
                'SELECT * FROM tweets WHERE status_id = ?',
                tweet.id_str
            );
            Ti.API.debug('Found: ' + rows.getRowCount() );
            if ( rows.getRowCount() > 0 ) continue;

            var res = this.db.execute(
                'INSERT INTO tweets (screen_name, profile_image_url, tweet_text, status_id, created_at) VALUES(?,?,?,?,?)',
                tweet.user.screen_name,
                tweet.user.profile_image_url,
                tweet.text,
                tweet.id_str,
                tweet.created_at
            );
            Ti.API.debug('Add to DB');
        }
        this.close();
        return true;
    };


    this.open();
    this.db.execute('CREATE TABLE IF NOT EXISTS tweets (screen_name TEXT, profile_image_url TEXT, tweet_text TEXT, status_id TEXT, created_at TEXT)');
    this.close();
};

では,先頭部分から解説していきましょう。最初に(1)の部分で接続するデータベースの名前をオブジェクのプロパティにセットします。

さらに次の部分(2), (3)でopenとcloseメソッドを定義しています。このメソッドはデータベースの処理を始めるときのTitanium.Database.openの処理と,終了するときのcloseの処理を簡単に呼び出せるようにしているだけです。openメソッドの中で使われている,Titanium.Database.openメソッドがデータベース接続を始めるメソッドで,このメソッドが返すTitatnium.Databaseオブジェクトに対して,各データベース処理を行っていくことになります。

この次に(4)で定義されているaddTweetメソッドは,タイムラインの情報をもった配列tweetsを受け取ることで,その中から保存が必要なものだけをデータベースに保存するメソッドです。まずthis.open()でデータベースに接続します。その後タイムライン中の各ツイートに対して,既に保存されていないか確認し(A),保存されていなかった場合はデータベースに保存する(B),という処理をしています。(A)の部分を行っているのが,(5)の

var rows = this.db.execute(
  'SELECT * FROM tweets WHERE status_id = ?',
   tweet.id_str
);
Ti.API.debug('Found: ' + rows.getRowCount() );
if ( rows.getRowCount() > 0 ) continue;

の部分で,this.dbに保存されているTi.DataBaseオブジェクトに対してSQLのSELECT文を発行しています。第一引数のSQL文に含まれる '?' は,第二引数以降に変換される,いわゆるプレースホルダです。

SQLを発行した結果なにかデータが返ってきている場合は,executeメソッドの返り値オブジェクトTitanium.Database.ResultSetのgetRowCount()メソッドで確認できます。この例ではデータが返っていた場合,つまりgetRowCount()が0より大きかった場合はすでにそのツイートが保存されている状態なので,何もせず次のツイートを確かめるように実装しています。

さらに次に続く部分が,(B)のデータベースにデータを保存している部分で,INSERT文を発行することでデータベースの各カラムにツイートの情報を保存しています。

タイムライン中の全てのツイートに対してこの処理を行った後,this.close()を呼び出して,データベースへの接続を終了しています。

もう一つ重要なのは,saveTweetメソッドの定義のあとで,

    this.db.execute('CREATE TABLE IF NOT EXISTS tweets (screen_name TEXT, profile_image_url TEXT, tweet_text TEXT, status_id TEXT, created_at TEXT)');

という文がある点です。この文は,このTweetDBオブジェクがnewされた時に一度だけ実行されるもので,tweetsというテーブルが存在しなかった場合にデータベースにtweetsテーブルを作るCREATE TABLE文が書かれています。テーブルの定義はここに書かれているわけです。

これでデータベースにツイートを格納する準備はできたので,タイムラインを取得する部分でツイートを保存するようにしてみましょう。

var db = new TweetDB();
twitterApi.statuses_home_timeline(
    {
        onSuccess: function(response){
            db.addTweets(response);
            updateTimeline(response);
        },
        onError: function(error){
            Ti.API.error(error);
        }
    }
);

まずTweetDBオブジェクを作成し自分のタイムラインを取得したときに,その内容をaddTweetsメソッドに渡しているだけですが,これでデータベースにツイートが保存できたはずです。

著者プロフィール

倉井龍太郎(くらいりゅうたろう)

株式会社はてな アプリケーションエンジニア。

スマートフォンアプリからSQLチューニングまで幅広く格闘中。好きな言語はRuby。

URLhttp://d.hatena.ne.jp/r_kurain/
Twitter@kurain

コメント

  • SearchBarが表示されません。

    win1.add(search);
    としている箇所を
    tableView.add(search);
    としてやると表示できました。

    Commented : #4  mura (2011/12/02, 11:42)

  • SQL文がエラー

    var rows = this.db.execute(
    'SELECT * FROM tweets WHERE screen_name like ?',
    '%' + screen_name + '%'
    );

    で,
    シングルコーテーションで検索文字列で括っていないため正しく検索できていません。

    Commented : #3  mura (2011/12/02, 11:37)

  • ソート順について

    created_atをTEXT型で生成するとORDER BY で正しく降順にタイムテーブルが表示されません。

    実装を簡単にするためにTEXTにしたのだと思いますが、ソートの問題をコメントしておく方がよいと思います。

    REAL型でDate.getTIme, Date.setTimeを使った場合には、ソートは正しくできました。

    Commented : #2  竹本 浩 (2011/07/30, 18:17)

  • ソースコード

    twitter_setting.jsのソースコードのアップをよろしくお願い致します。

    Commented : #1  iphone4 (2011/04/25, 14:16)

コメントの記入