2012年11月7日水曜日

SQLiteの定義済みのファイルを使う

 SQLite は、ファイルベースのため、対象ファイルを指定することによって簡単に別のデータべヘスにアクセス出来る。と言うよりも、むしろ、目的でファイルに分けると言った感じです。そうなるとすぐに思い当たるのが、データベースを定義しておきこのファイルをそのまま使えないのかということ。少しものぐさかもしれませんが時間短縮にもなるし、SQLiteのGUIベース管理ツールで管理していると真っ先に思いつくことなので、色々と調べてみました。するとやはりありました。
 やり方は至って簡単で、 asset フォルダに使いたいデータベースファイルを設置しておき、データベースを開く前にコピーしてやるといい。コンストラクタ時はファイルはなくてもいいので、オープンする直前でいい。

Context.getDatabasePath(String name)

メソッドで指定したデータベースが存在するパスを取得して、

SQLiteDatabase.openDatabase(String path, CursorFactory factory, int flags)

 メソッドを使って、android のストレージにファイルが有るかをチェックします。このメソッドは、ファイルが無ければ例外を返してくるので、オブジェクトを返さなかったらファイルが無かったと処理させれば良い。

 ファイルが存在していないのならば、FileStream を使って、android のストレージへコピーすれば良い。しかし、ここで、勘の良い人は気づくと思います。

「どこに保存されるの?」

 そう、保存されるのば内蔵メモリの領域。場所はインストールされたアプリケーションごとの領域です。せっかくSDカードがあるのに気持ち悪いですよね。そんな時は、SDカードがマウントされているなら、内蔵ではなく、そっちにコピーする方法あります。

 まずは、以下のメソッドでSDカードがマウントされているかをチェックします。

Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

これが、true を返せば、SDカードはマウントされています。以下のメソッドでマウント先のパスを取得します。

Environment.getExternalStorageDirectory() 

 取得した下に適当なディレクトリを付加したパスをデータベースファイルに付加して存在チェックを行い、なければそこにコピーという手順で任意のフォルダへコピーできます。

 ここで、注意しなければならないことは、permission でSDカードを許可しないと行けません。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

タグを追加して、アプリケーションがSDカードにアクセスすることを許可しないとSDカードへの保存ができません。







SQLite を使う。

 アプリといえば必ずついて回るのがデータをどうするか。簡単なアプリでもデータを管理するのには悩みます。しかし、Android は標準でSQLite 対応しているので、これを使わない手はありません。

SQLiteOpenHelper
SQLiteDatabase

これらの2つ使えば、簡単にSQLite データベースが使えます。

 SQLiteOpenHelper は、これをスーパークラスとしたサブグラスを作成し、サブラスのコンストラクタでスーパークラスのコンストラクタを呼ぶようにし、以下のメソッドをオーバーライドします。

public void onCreate(SQLiteDatabase db)
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

 これらは、抽象化されたメソッドなので、必ずオーバーライドして実装する必要があります。また、コンストラクタですが、スーパークラスでは、

SQLiteOpenHelper(Context context, String name,  CursorFactory factory, int version)

 として、定義されてます。
 サブクラスのコンストラクタでは、必要な引数のみ受けるようにして、スーパークラスのメソッド呼ぶ時に加工して呼ぶのが良いです。
 ここで、色々な文献をみてもしっくり来ないのが、CursorFactory です。どうやら、独自のクエリの結果セットを使う時に指定するらしいのですが、そのようなことはまずないので null 指定でOKだとか、まあ、問題ないならばそれ以上は追求しないことに。
 最後の version も、バージョン管理するまでもないものには 1 でいいでしょう。

 さて、SQLiteDatabase がどこかに行ってますが、これは、SQLiteOpenHelper の以下の2つのメソッド、

getWritableDatabase()
getReadableDatabase()

 返します。
 返されたオブジェクトを使って、データベースとやりとりします。




レイアウトはコードか、XMLか

 画面を作っていて感じたのは、コントロールのレイアウトをコードでするか、XML でするかです。
 
 私は、大外枠をXMLで作成し、動的になったりする時にコードで行う。XML で作成したコントロールは、onCreate メソットで、ヒモ付を行なうのが後々いいのかと。また、キャプションもXMLで定義しておく癖をつければ、ローカライズや、同じような表現の時にメンテする時が楽なのかと。このあたり、完全に分離してくれているのはいいです。

 ただ、Eclipse のAll in One で開発していると、楽な分弊害として、XML ファイルを編集中でも、ツールバーから実行をかけられてします。しかし、これをすると、Android アプリは立ち上がらずに、xxxx.out.xml というファイルを作って実行できなくなってしまう。必ず、.java 等のファイルをピックしてから実行する必要があります。もし、そのようにしてしまったら、少し時間を置いて、できてしまった xxxx.out.xml ファイルを削除すれば、実行出来るようになります。このファイルはできてからすぐには消えないので、焦らずに閉じで少し時間を置けばちゃんと消えます。

 あと、XML で作ると、 Graphical Layout が使えますが、これでレイアウトの変更もあまりしないほうが良い。RelativeLayout では、思った場所に配置できずにイライラします。
 とりあえず配置したら、XML を直接編集して、確認に Graphical Layout を使うのがベター。そんな感じです。

環境構築

 まずは、環境構築。
 Android はJavaで作ると言うことで、Eclipse を使います。インストール方法や、細かいことは、過去のことで、解決、スルーだったので申し訳ないですが、インストールしたものだけ載せておきます。


■Windows
  ・Android SDK tools
  ・Eclipse 3.7 with Pleiades
  ・Eclipse ADT プラグイン
  ・SQLite3
  ・PupSQL

■Ubuntu

  ・Android SDK tools
  ・Eclipse 3.7
  ・Eclipse ADT プラグイン
  ・SQLite3
  ・SQLiteのGUIツール(あとで)

と、いったところ。
この辺は、躓くことなく行くと思います。
ただ、AVD(仮想デバイス)が重いんですよね。特にWindows。使っているマシンがヘタレというのもありますが、なんともしがたいです。最終的には実機でテストとなるので、このあとは、所持しているデバイスのドライバをインストールします。

■Windows
 各デバイスごとのドライバーをメーカーサイトより、ダウンロードしてインストールします。インストールするのはちょっと手間かもしれません。物によってはツールの中とかなので、余分なツールが必要ない時は、カスタムインストールでドライバのみを選択する必要もあります。

■Ubuntu
 デバイスをデバッグモードにして、USBに挿せばデバイスは見えるのですが、シリアルナンバー等が取得できないので、定義ファイルを作らなくては行けません。
 詳しくは、http://developer.android.com/tools/device.html を参照すると、何やら英語で色々とか書かれています。簡単に言うと、こんな感じ。

  1. /etc/udev/rules.d/ というディレクトリに 51-android.rules というファイルを作成。
  2. 51-android.rules には、以下のように書く。
  SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev"
  3. ファイルを作成したら、以下のコマンドを実行する。
    chmod a+r /etc/udev/rules.d/51-android.rules
  4. 確認として、SDK のadb コマンドで adb devices を実行
  5. 正しいデバイスリストが表示されればOK

と、こんな感じ。全てスーパーユーザーとして実行します。

ATTR{idVendor}=="0bb4" は、ベンダ事に決められたコードで、当該ページに一覧が出ているので参考にしてください。

GROUP="plugdev" は、デバイスによっては要らない感じす。少なくとも、シャープは要らないですが、HTCは必要。当該ページもHTCの例としてあげてます。

 ちなみに、私は、実機をIS05と、HTC J を持っているので、51-android.rules のファイルには、以下のように書いてます。

SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="04dd", MODE="0666"

 これで、でデバッグ時に実機が使えます。
 実際にデバッグや実行を行う時は、「実行」→「実行構成」 で「ターゲット」を「手動(Allways prompt to pick device)」に切り替えて、実行すれば、実行するデバイスを選択出ます。

 あとは、お好みのプラグインやらインストールして環境構築は終了です。


はじめに

 本当は、開発を始めた時からつけていればよかったのですが、最近調べたことが解決したままにしておいてあとでまた、同じ事を調べているようなこともあったり、なかったり。そこで備忘録的なものをつけて行こうかと思います。

 同じように行き詰まった人の助けになれば幸いです。

 ちなみに、メインはOSをubuntu で、サブにWinXP or 7 そんな感じにやってます。