「第一行コード」学習ノート第6章

12063 ワード

第6章データストアの全方案、持久化技術を詳しく説明する。
一:ファイル保存
  • は、データをファイルに格納する(Javaストリームを使用してファイルにデータを書き込む)。
  • ここでは、オプンFileOutput()の方法によりFileOutputStreamオブジェクト
  • を得ることができます。
  • その後、Output Stream Writerオブジェクト
  • を構築する。
  • は次にOutputStream Writerを使用してバッファローオブジェクト
  • を構築する。
  • そうすれば、BuffereWriter.writeを通じてテキストの内容をファイルに書き込むことができます。
  • ファイルストリームを閉じる
  • public void save() {
        String data = "Data to save";
        
        FileOutputStream out = null;
        BufferedWriter writer = null;
        
        try {
            out = openFileOutput("data", Context.MODE_PRIVATE);  // 1 FileOutputStream
            writer = new BufferedWriter(new OutputStreamWriter(out));  // 2 BufferedWriter、3 BufferedWriter
            writer.write(data);  // 4 
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null) {
                    writer.close(); // 5
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
  • ファイルからデータを読み出す
  • まずopenFileInput()法によりFileInputStreamオブジェクトを取得しました。
  • はその後、Input Stream Readerオブジェクトを構築し、
  • は、次いで、InputStream Readerを使用して、バッファロー・エディターオブジェクトを構築し、
  • これにより、BufferedReaderを通じて、ファイル中のすべてのテキスト内容を全部読み出して一つのStringBuiderオブジェクトに格納することができます。
  • ファイルストリームを閉じる
  • は最後に読み取った内容を返すだけでいいです。
  • public String load() {
        FileInputStream in = null;
        BufferedReader reader = null;
        StringBuilder content = new StringBuilder();
        
        try {
            in = openFileInput("data"); //1 FileInputStream
            reader = new BufferedReader(new InputStreamReader(in)); // 2、3
            String line = "";
            while ((line = reader.readLine()) != null) {    //4
                content.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close(); //  5
                } 
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return content.toString();
    }
    
    二:SharedPreferences保存
  • は、SharedPreferencesにデータを格納する。
  • は、まずShardPreferencesオブジェクトを取得する必要がある(3つの方法で取得できる)。
  • Contectクラスのget SharedPreferences()方法
  • Activityクラスのget Preferences()メソッド(この方法は、自動的に現在のアクティビティのクラス名をShardPreferencesのファイル名とします)
  • PreferenceManagerクラスのget Default SharedPreferences()方法(これは静的方法であり、Conteextパラメータを受信し、現在のアプリケーションのパケット名をプレフィックスとして自動的に使用してShared Preferencesファイルと命名する)
  • は、SharedPreferencesオブジェクトのedit()方法を呼び出して、SharedPreferences.Editorオブジェクトを取得する。
  • は、1つのブール型データを追加すると、PutBoolean法
  • を使用して、ShardPreferences.Editorオブジェクトにデータを追加します。
  • は、comit()またはappy()方法を呼び出して、追加されたデータを提出し、データ記憶動作を完了する。
  • シェアプレスからデータを読み出す
  • は、まずget SharedPreferences()法によりShardPreferencesオブジェクトを得て、
  • はその後、そのget String()、getInt()とget Boolean()を呼び出して、前に記憶されているデータを取得します。対応する値が見つからないと、
  • の代わりに方法によって入力されたデフォルト値を使用します。
    三:SQLiteデータベース記憶
  • は、データベースgetReadable Database()とgetWritable Database()を作成する。これらの2つの方法は、既存のデータベースを作成または開くことができます。データベースが存在する場合は、直接に開くことができます。そうでない場合は、新しいデータベースを作成し、データベースを読み書きできるオブジェクトを返します。異なっているのは、データベースが書き込み不可の場合(ディスク領域がいっぱいの場合)getReadable Database()方法で戻ったオブジェクトは読み取り専用でデータベースを開きますが、getWritable Database()方法では異常が発生します。
  • カスタムデータベースタイプMyDatabaseHelperを新設し、SQLiteOpenHelper
  • を継承する。
    public class MyDatabaseHelper extends SQLiteOpenHelper {
        private Context mContext;
        
        //    primary key  id      ,   autoincrement      id      。
        public static final String CREATE_BOOK = "create table book ("
        + "id integer primary key autoincrement, "
        + "author text, "
        + "price real, "
        + "pages integer, "
        + "name text)";
    
        public MyDatabaseHelper(Context context, String name, CursorFactory factory, int version) {
            super(context, name, factory, version);
            mContext = context;
        }
    
        //       
        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(CREATE_BOOK);
            Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
        }
        
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }
    
    2.               MyDatabaseHelper  ,                    BookStore.db,      1
    
    dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
    
    3.     Create database            getWritableDatabase()  。
    
    dbHelper.getWritableDatabase();
    
    (このようにCreate databaseボタンを初めてクリックすると、現在のプログラムにはBook Stre.dbというデータベースがないことが検出され、このデータベースを作成し、MyDatabaseHelperのonCreate()を呼び出します。このようにBookテーブルは作成され、再度Create databaseボタンをクリックすると、Book Stree.dbデータベースが既に存在していることが分かりますので、これ以上作成しません。これはsdkのplotform-toolsディレクトリの下に保存されています。コマンドラインでこのツールを使用するには、まず環境変数に経路を配置する必要があります。(adbshellを入力すると、デバイスのコンソールに入ってデータベース操作を行う)
  • アップグレードデータベース
  • データベースクラスで新しいテーブルを定義する
  • public static final String CREATE_CATEGORY = "create table Category ("
        + "id integer primary key autoincrement, "
        + "category_name text, "
        + "category_code integer)";
    
  • 新規データテーブルコマンド
  • をデータベースクラスのonCreate方法に追加します。
        db.execSQL(CREATE_CATEGORY);
    
  • コマンドをデータベースクラスのonUpgradeメソッドに追加します。(既存のテーブルを削除して、新規作成します。)
  •     db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    
  • コードの中でデータベースを更新したいところは以下のコードを呼び出します。
        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
        dbHelper.getWritableDatabase();
    
  • 追加データ(getReadable Database()またはgetWritable Database()方法はいずれもSQLiteDatabaseオブジェクトに戻り、このオブジェクトを介してデータの追加、削除、更新などの動作が可能になる。
  • まずSQLiteDatabaseオブジェクトを取得しました。
  • その後、ContintValuesを使用して追加するデータを組み立てる

  •     SQLiteDatabase db = dbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        //           
        values.put("name", "The Da Vinci Code");
        values.put("author", "Dan Brown");
        values.put("pages", 454);
        values.put("price", 16.96);
        db.insert("Book", null, values); //         
        values.clear();
        //           
        values.put("name", "The Lost Symbol");
        values.put("author", "Dan Brown");
        values.put("pages", 510);
        values.put("price", 19.95);
        db.insert("Book", null, values); // 
    
  • データを更新する
  •     SQLiteDatabase db = dbHelper.getWritableDatabase();
        
        ContentValues values = new ContentValues();
        values.put("price", 10.99);
        
        //          SQL    where  ,       name  ?  , ?      ,                                       
        db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" }); //     The Da Vinci Code          10.99
    
  • データを削除する
  •     SQLiteDatabase db = dbHelper.getWritableDatabase();
        db.delete("Book", "pages > ?", new String[] { "500" });
    
  • クエリデータ(Cursorオブジェクト)
  •     SQLiteDatabase db = dbHelper.getWritableDatabase();
       
        Cursor cursor = db.query("Book", null, null, null, null, null, null);
        //            Cursor  ,        moveToFirst()                 ,           ,            
        if (cursor.moveToFirst()) {
            do {
                //    Cursor   ,       
                String name = cursor.getString(cursor.getColumnIndex("name"));
                String author = cursor.getString(cursor.getColumnIndex("author"));
                int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                double price = cursor.getDouble(cursor.getColumnIndex("price"));
                
                Log.d("MainActivity", "book name is " + name);
                Log.d("MainActivity", "book author is " + author);
                Log.d("MainActivity", "book pages is " + pages);
                Log.d("MainActivity", "book price is " + price);
            } while (cursor.moveToNext());
            }
        cursor.close();
        }
    
  • *SQLオペレーティングデータベースを使用する(sql文を直接使用して上記の操作を行う)
  • データを追加する方法は以下の通りです。
  •     db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",
        new String[] { "The Da Vinci Code", "Dan Brown", "454", "16.96" });
        db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",
        new String[] { "The Lost Symbol", "Dan Brown", "510", "19.95" });
    
  • データの更新方法は以下の通りです。
  •     db.execSQL("update Book set price = ? where name = ?", new String[] { "10.99","The Da Vinci Code" });
    
  • データを削除する方法は以下の通りです。
  •     db.execSQL("delete from Book where pages > ?", new String[] { "500" });
    
  • データを検索する方法は以下の通りです。
  •     db.rawQuery("select * from Book", null);
    
  • SQLiteデータベースの最適な実践
  • 事務を使用して(事務の特性は、一連の操作を全部完成させるか、または一つもできないことを保証します。)
  •     SQLiteDatabase db = dbHelper.getWritableDatabase();
        db.beginTransaction(); //      
        
        try {
        
            //    
            db.delete("Book", null, null);  
            
            if (true) {
                //             ,     ,     catch  ,             ,       ,              ,      。
                throw new NullPointerException();
            }
            
            //    
            ContentValues values = new ContentValues();
            values.put("name", "Game of Thrones");
            values.put("author", "George Martin");
            values.put("pages", 720);
            values.put("price", 20.85);
            db.insert("Book", null, values);
            db.setTransactionSuccessful(); //          
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {//        
            db.endTransaction(); //      
        }
    
  • アップグレードデータベースの最適な書き方(各バージョンにそれぞれ変更された内容を与え、その後、OnUpgrade()方法で現在のデータベースのバージョン番号を判断し、対応する変更を実行する)
  • //需要1:データベースにもう一枚のCategory表を追加します。
  • OneCreate()の方法では、建表文を追加しました。
  •     public void onCreate(SQLiteDatabase db) {
            db.execSQL(CREATE_BOOK);
            db.execSQL(CREATE_CATEGORY);    //         
        }
    
  • その後、OnUpgrade()方法にswitch判定を追加しました。もしユーザの現在のデータベースのバージョン番号が1なら、Category表を作成するだけです。このようにユーザーが直接インストールした第二版のプログラムである場合、両表を一緒に作成します。ユーザが第二版のプログラムを使って第一版のプログラムをカバーしてインストールすると、アップグレードデータベースの操作に入ります。この時、Bookテーブルは既に存在しますので、Category表を作成するだけでいいです。
  • public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        switch (oldVersion) {
            case 1:
                db.execSQL(CREATE_CATEGORY);
            default:
        }
    }
    
    //需要2:Book表にcategoryを追加する必要があります。idのフィールド
  • 元の建表語句を修正して、categoryを追加します。idのフィールド
  •     public static final String CREATE_BOOK = "create table Book ("
        + "id integer primary key autoincrement, "
        + "author text, "
        + "price real, "
        + "pages integer, "
        + "name text, "
        + "category_id integer)";
    
  • OUpgrade方法を修正する
  •     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            switch (oldVersion) {
                case 1:
                    db.execSQL(CREATE_CATEGORY);
                case 2:
                    db.execSQL("alter table Book add column category_id integer");
                default:
            }
        }
    
    注:
  • switchの中の一つのcaseの最後は全部breakを使っていないです。なぜこのようにしますか?これは別のバージョンのアップグレード時に、毎回のデータベース修正が全部実行されることを保証するためです。
  • はこのようにしてデータベースのアップグレードを維持します。バージョンがどのように更新されても、データベースのテーブル構造は最新であり、テーブルのデータも完全に失われません。