end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

sqlite(db)操作入門(写経)

http://y-anz-m.blogspot.jp/2011/01/android-sqline-database.html
↑このurlの写経で、dbにある単語をListViewに一覧表示します

DbHelper

perlで言うところのDBI。どのアプリであっても、同様になるはずです。

package jp.end0tknr.dbtest;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;

public class DbHelper extends SQLiteOpenHelper {
    //The Android のデフォルトでのデータベースパス  
    private static String DB_PATH = "/data/data/jp.end0tknr.dbtest/databases/";
    
    private static String DB_NAME = "chr_kana";
    private static String DB_NAME_ASSET = "chr_kana.sqlite3";
    
    private SQLiteDatabase mDataBase;
    private final Context mContext;
    
    public DbHelper(Context context) {
        super(context, DB_NAME, null, 1);
        this.mContext = context;  
    }  
    
    //asset に格納したデータベースをコピーするための空のデータベースを作成する 
    public void createEmptyDataBase() throws IOException{  
        boolean dbExist = checkDataBaseExists();  

        if(dbExist){  
            // すでにデータベースは作成されている  
        }else{
            // このメソッドを呼ぶことで、空のデータベースが  
            // アプリのデフォルトシステムパスに作られる  
            this.getReadableDatabase();
            try {
                // asset に格納したデータベースをコピーする  
                copyDataBaseFromAsset();
            } catch (IOException e) {  
                throw new Error("Error copying database");
            }
        }
    }

    //再コピーを防止するために、DBの存在check (存在=true)
    private boolean checkDataBaseExists() {  
        SQLiteDatabase checkDb = null;  
        
        try{  
            String dbPath = DB_PATH + DB_NAME;  
            checkDb =
                    SQLiteDatabase.openDatabase(
                            dbPath, null, SQLiteDatabase.OPEN_READONLY);  
        }catch(SQLiteException e){  
            // データベースはまだ存在していない  
        }
        
        if(checkDb != null){
            checkDb.close();
        }
        return checkDb != null ? true : false;  
    }
    
    /** 
     * asset に格納したデーだベースをデフォルトの 
     * データベースパスに作成したからのデータベースにコピーする 
     * */  
    private void copyDataBaseFromAsset() throws IOException{
        
        // asset 内のデータベースファイルにアクセス  
        InputStream mInput = mContext.getAssets().open(DB_NAME_ASSET);
        
        // デフォルトのデータベースパスに作成した空のDB
        String outFileName = DB_PATH + DB_NAME;
        
        OutputStream mOutput = new FileOutputStream(outFileName);
        
        // コピー  
        byte[] buffer = new byte[1024];
        int size;  
        while ((size = mInput.read(buffer)) > 0){
            mOutput.write(buffer, 0, size);
        }
        
        //Close the streams
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }
    
    public SQLiteDatabase openDataBase() throws SQLException{  
        //Open the database  
        String myPath = DB_PATH + DB_NAME;  
        mDataBase =
                SQLiteDatabase.openDatabase(
                        myPath, null, SQLiteDatabase.OPEN_READONLY);  
        return mDataBase;  
    }
    
    @Override
    public void onCreate(SQLiteDatabase arg0) {  
    }  
  
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
    }
    
    @Override
    public synchronized void close() {
        if(mDataBase != null) mDataBase.close();
        super.close();  
    }
}

DbTestActivity

perlでの生sql実行と比較すると、文化の違いを感じるところがいくつかありますが、これに関してはsrc中のコメントをご覧下さい。

package jp.end0tknr.dbtest;

import java.io.IOException;
import android.app.Activity;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class DbTestActivity extends Activity {
    private DbHelper mDbHelper;  
    private SQLiteDatabase db;
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
	        
        setDatabase(); //DB接続
        
        String[] words = findWords(); //単語取得(select sql実行)

	//取得した単語一覧の表示
        ListView listView = (ListView)findViewById(R.id.WordList);
        ArrayAdapter<String> adapter =
                new ArrayAdapter<String>(
                        this, android.R.layout.simple_list_item_1, words);
        listView.setAdapter(adapter);
    }


    @Override  
    public void onDestroy() {
        db.close();  
        super.onDestroy();
    }
    
    
    private String[] findWords(){
        //selectではrawQuery()、update系ではcompileStatement()で
        //?によるプレーすホルダが使えるみたい
        String sql = "select * from my_word where word like ?";
        Cursor c = db.rawQuery(sql,new String[]{"%%"});
        
        c.moveToFirst();
	//そう言えば、javaの配列って、固定長だった。
	//可変長配列を利用するのであれば、ArrayListを使いましょう
        String[] retStrs = new String[c.getCount()];
        for (int i = 0; i < c.getCount(); i++) {
            retStrs[i] = c.getString(1);
            c.moveToNext();
        }
        c.close();
        return retStrs;
    }
    
    //DB connect
    private void setDatabase() {  
        mDbHelper = new DbHelper(this);   
        try {  
            mDbHelper.createEmptyDataBase();  
            db = mDbHelper.openDataBase();  
        } catch (IOException ioe) {  
            throw new Error("Unable to create database");  
        } catch(SQLException sqle){  
            throw sqle;  
        }
    }
}

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

<ListView 
    android:id="@+id/WordList"
    android:layout_height="fill_parent" 
    android:layout_width="fill_parent" ></ListView>
</LinearLayout>