Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 《第一行代碼》——第6章 數據存儲全方案,詳解持久化技術

《第一行代碼》——第6章 數據存儲全方案,詳解持久化技術

編輯:關於Android編程

瞬時數據是指那些存儲在內存當中,有可能會因為程序關閉或其他原因導致內存被回收而丟失的數據。這對於一些關鍵性的數據信息來說是絕對不能容忍的,誰都不希望自己剛發出去的一條微博,刷新一下就沒了吧。那麼怎樣才能保證讓一些關鍵性的數據不會丟失呢?這就需要用到數據持久化技術了。

持久化技術簡介

數據持久化就是指將那些內存中的瞬時數據保存到存儲設備中,保證即使在手機或電腦關機的情況下,這些數據仍然不會丟失。保存在內存中的數據是處於瞬時狀態的,而保存在存儲設備中的數據是處於持久狀態的,持久化技術則是提供了一種機制可以讓數據在瞬時狀態和持久狀態之間進行轉換。
Android系統中主要提供了三種方式用於簡單地實現數據持久化功能,即文件存儲、SharedPreference存儲以及數據庫存儲。當然,除了這三種方式之外,你還可以將數據保存在手機的SD卡中,不過使用文件、SharedPreference或數據庫來保存數據會相對更簡單一些,而且比起將數據保存在SD卡中會更加的安全。

文件存儲

文件存儲是Android中最基本的一種數據存儲方式,它不對存儲的內容進行任何的格式化處理,所有數據都是原封不動地保存到文件當中的,因而它比較適合用於存儲一些簡單的文本數據或二進制數據。如果你想使用文件存儲的方式來保存一些較為復雜的文本數據,就需要定義一套自己的格式規范,這樣方便於之後將數據從文件中重新解析出來。
下面是一個將數據存儲到文件中和從文件中讀取數據的例子,代碼如下:
布局文件很簡單,就只包含一個EditText控件:



    


主要代碼還是在MainActivity類裡面來實現的:

public class MainActivity extends Activity {

    private EditText edit;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        edit = (EditText) findViewById(R.id.edit);
    String inputText = load();
    if (!TextUtils.isEmpty(inputText)) {//對字符串進行非空判斷的時候使用了 TextUtils.isEmpty()方法,這是一個非常好用的方法,它可以一次性進行兩種空值的判斷。當傳入的字符串等於null或者等於空字符串的時候,這個方法都會返回true,從而使得我們不需要單獨去判斷這兩種空值,再使用邏輯運算符連接起來了。
       edit.setText(inputText);
       edit.setSelection(inputText.length());
       Toast.makeText(this, "Restoring succeeded", Toast.LENGTH_SHORT).show();
    }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        String inputText = edit.getText().toString();
        save(inputText);
    }

//將數據存儲到文件中
    public void save(String inputText) {
        FileOutputStream out = null;
        BufferedWriter writer = null;
        try {
            out = openFileOutput("data", Context.MODE_PRIVATE);//Context類中提供了一個openFileOutput ()方法,可以用於將數據存儲到指定的文件中。這個方法接收兩個參數,第一個參數是文件名,在文件創建的時候使用的就是這個名稱,注意這裡指定的文件名不可以包含路徑,因為所有的文件都是默認存儲到/data/data//files/目錄下的。第二個參數是文件的操作模式,主要有兩種模式可選,MODE_PRIVATE和MODE_APPEND。其中MODE_PRIVATE是默認的操作模式,表示當指定同樣文件名的時候,所寫入的內容將會覆蓋原文件中的內容,而MODE_APPEND則表示如果該文件已存在就往文件裡面追加內容,不存在就創建新文件。其實文件的操作模式本來還有另外兩種,MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE,這兩種模式表示允許其他的應用程序對我們程序中的文件進行讀寫操作,不過由於這兩種模式過於危險,很容易引起應用的安全性漏洞,現已在Android 4.2版本中被廢棄。
            writer = new BufferedWriter(new OutputStreamWriter(out));
            writer.write(inputText);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

//從文件中讀取數據
public String load() {
        FileInputStream in = null;
        BufferedReader reader = null;
        StringBuilder content = new StringBuilder();
        try {
            in = openFileInput("data");//Context類中還提供了一個 openFileInput()方法,用於從文件中讀取數據。這個方法要比 openFileOutput()簡單一些,它只接收一個參數,即要讀取的文件名,然後系統會自動到/data/data//files/目錄下去加載這個文件,並返回一個 FileInputStream對象,得到了這個對象之後再通過Java流的方式就可以將數據讀取出來了。
            reader = new BufferedReader(new InputStreamReader(in));
            String line = "";
            while ((line = reader.readLine()) != null) {
                content.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return content.toString();
    }

}

SharedPreferences存儲

SharedPreferences是使用鍵值對的方式來存儲數據的。也就是說當保存一條數據的時候,需要給這條數據提供一個對應的鍵,這樣在讀取數據的時候就可以通過這個鍵把相應的值取出來。而且SharedPreferences還支持多種不同的數據類型存儲,如果存儲的數據類型是整型,那麼讀取出來的數據也是整型的,存儲的數據是一個字符串,讀取出來的數據仍然是字符串。

將數據存儲到SharedPreferences 中
要想使用SharedPreferences來存儲數據,首先需要獲取到SharedPreferences對象。Android中主要提供了三種方法用於得到SharedPreferences對象。

Context類中的getSharedPreferences()方法
此方法接收兩個參數,第一個參數用於指定SharedPreferences文件的名稱,如果指定的文件不存在則會創建一個,SharedPreferences文件都是存放在/data/data//shared_prefs/目錄下的。第二個參數用於指定操作模式,主要有兩種模式可以選擇,MODE_PRIVATE和MODE_MULTI_PROCESS。MODE_PRIVATE仍然是默認的操作模式,和直接傳入0效果是相同的,表示只有當前的應用程序才可以對這個SharedPreferences文件進行讀寫。MODE_MULTI_PROCESS則一般是用於會有多個進程中對同一個SharedPreferences文件進行讀寫的情況。類似地,MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE這兩種模式已在Android 4.2版本中被廢棄。 Activity類中的getPreferences()方法
這個方法和Context中的getSharedPreferences()方法很相似,不過它只接收一個操作模式參數,因為使用這個方法時會自動將當前活動的類名作為SharedPreferences的文件名。 PreferenceManager類中的getDefaultSharedPreferences()方法
這是一個靜態方法,它接收一個Context參數,並自動使用當前應用程序的包名作為前綴來命名SharedPreferences文件。
得到了SharedPreferences對象之後,就可以開始向SharedPreferences文件中存儲數據了,主要可以分為三步實現。
調用SharedPreferences對象的edit()方法來獲取一個SharedPreferences.Editor對象。 向SharedPreferences.Editor對象中添加數據,比如添加一個布爾型數據就使用putBoolean方法,添加一個字符串則使用putString()方法,以此類推。 調用commit()方法將添加的數據提交,從而完成數據存儲操作。

從SharedPreferences 中讀取數據

SharedPreferences對象中提供了一系列的get方法用於對存儲的數據進行讀取,每種get方法都對應了 SharedPreferences. Editor中的一種put方法,比如讀取一個布爾型數據就使用getBoolean()方法,讀取一個字符串就使用getString()方法。這些get方法都接收兩個參數,第一個參數是鍵,傳入存儲數據時使用的鍵就可以得到相應的值了,第二個參數是默認值,即表示當傳入的鍵找不到對應的值時,會以什麼樣的默認值進行返回。

SharedPreferences存儲確實要比文本存儲簡單方便了許多,應用場景也多了不少,比如很多應用程序中的偏好設置功能其實都使用到了 SharedPreferences技術。

SQLite是一款輕量級的關系型數據庫,它的運算速度非常快,占用資源很少,通常只需要幾百K的內存就足夠了,因而特別適合在移動設備上使用。SQLite不僅支持標准的SQL語法,還遵循了數據庫的ACID事務,所以只要你以前使用過其他的關系型數據庫,就可以很快地上手SQLite。而SQLite又比一般的數據庫要簡單得多,它甚至不用設置用戶名和密碼就可以使用。Android正是把這個功能極為強大的數據庫嵌入到了系統當中,使得本地持久化的功能有了一次質的飛躍。

創建數據庫

Android為了讓我們能夠更加方便地管理數據庫,專門提供了一個SQLiteOpenHelper幫助類,借助這個類就可以非常簡單地對數據庫進行創建和升級。既然有好東西可以直接使用,那我們自然要嘗試一下了,下面我就將對SQLiteOpenHelper的基本用法進行介紹。
首先你要知道SQLiteOpenHelper是一個抽象類,這意味著如果我們想要使用它的話,就需要創建一個自己的幫助類去繼承它。SQLiteOpenHelper中有兩個抽象方法,分別是onCreate()和onUpgrade(),我們必須在自己的幫助類裡面重寫這兩個方法,然後分別在這兩個方法中去實現創建、升級數據庫的邏輯。
SQLiteOpenHelper中還有兩個非常重要的實例方法,getReadableDatabase()和getWritableDatabase()。這兩個方法都可以創建或打開一個現有的數據庫(如果數據庫已存在則直接打開,否則創建一個新的數據庫),並返回一個可對數據庫進行讀寫操作的對象。不同的是,當數據庫不可寫入的時候(如磁盤空間已滿)getReadableDatabase()方法返回的對象將以只讀的方式去打開數據庫,而getWritableDatabase()方法則將出現異常。
SQLiteOpenHelper中有兩個構造方法可供重寫,一般使用參數少一點的那個構造方法即可。這個構造方法中接收四個參數,第一個參數是Context,這個沒什麼好說的,必須要有它才能對數據庫進行操作。第二個參數是數據庫名,創建數據庫時使用的就是這裡指定的名稱。第三個參數允許我們在查詢數據的時候返回一個自定義的Cursor,一般都是傳入null。第四個參數表示當前數據庫的版本號,可用於對數據庫進行升級操作。構建出SQLiteOpenHelper的實例之後,再調用它的getReadableDatabase()或getWritableDatabase()方法就能夠創建數據庫了,數據庫文件會存放在/data/data//databases/目錄下。此時,重寫的onCreate()方法也會得到執行,所以通常會在這裡去處理一些創建表的邏輯。
使用adb shell來對數據庫和表的創建情況進行檢查。
adb是Android SDK中自帶的一個調試工具,使用這個工具可以直接對連接在電腦上的手機或模擬器進行調試操作。它存放在sdk的platform-tools目錄下,如果想要在命令行中使用這個工具,就需要先把它的路徑配置到環境變量裡。
如果你使用的是Windows系統,可以右擊我的電腦→屬性→高級→環境變量,然後在系統變量裡找到Path並點擊編輯,將platform-tools目錄配置進去,如圖6.12所示。
這裡寫圖片描述
如果你使用的是Linux系統,可以在home路徑下編輯.bash_profile文件,將platform-tools目錄配置進去即可,如圖6.13所示:
這裡寫圖片描述vcnosbi1xL/Y1sbMqKOsyOfNvDYuMTTL+cq+oaM8YnIgLz4NCjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160906/20160906092910352.png" title="\" />
然後使用cd命令進行到/data/data/com.example.databasetest/databases/目錄下,並使用ls命令查看到該目錄裡的文件,如圖6.15所示。
這裡寫圖片描述

這個目錄下出現了兩個數據庫文件,一個正是我們創建的BookStore.db,而另一個BookStore.db-journal則是為了讓數據庫能夠支持事務而產生的臨時日志文件,通常情況下這個文件的大小都是0字節。
接下來我們就要借助sqlite命令來打開數據庫了,只需要鍵入sqlite3,後面加上數據庫名即可,如圖6.16所示。
這裡寫圖片描述
這時就已經打開了BookStore.db數據庫,現在就可以對這個數據庫中的表進行管理了。首先來看一下目前數據庫中有哪些表,鍵入.table命令,如圖6.17所示。
這裡寫圖片描述
可以看到,此時數據庫中有兩張表,android_metadata表是每個數據庫中都會自動生成的,不用管它,而另外一張Book表就是我們在MyDatabaseHelper中創建的了。這裡還可以通過.schema命令來查看它們的建表語句,如圖6.18所示。
這裡寫圖片描述
由此證明,BookStore.db數據庫和Book表確實已經是創建成功了。之後鍵入.exit或.quit命令可以退出數據庫的編輯,再鍵入exit命令就可以退出設備控制台了。

升級數據庫

添加數據

其實我們可以對數據進行的操作也就無非四種,即CRUD。其中C代表添加(Create),R代表查詢(Retrieve),U代表更新(Update),D代表刪除(Delete)。每一種操作又各自對應了一種SQL命令,如果你比較熟悉SQL語言的話,一定會知道添加數據時使用insert,查詢數據時使用select,更新數據時使用update,刪除數據時使用delete。但是開發者的水平總會是參差不齊的,未必每一個人都能非常熟悉地使用SQL語言,因此Android也是提供了一系列的輔助性方法,使得在Android中即使不去編寫SQL語句,也能輕松完成所有的CRUD操作。
調用SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()方法是可以用於創建和升級數據庫的,不僅如此,這兩個方法還都會返回一個SQLiteDatabase對象,借助這個對象就可以對數據進行CRUD操作了。
SQLiteDatabase中提供了一個insert()方法,這個方法就是專門用於添加數據的。它接收三個參數,第一個參數是表名,我們希望向哪張表裡添加數據,這裡就傳入該表的名字。第二個參數用於在未指定添加數據的情況下給某些可為空的列自動賦值NULL,一般我們用不到這個功能,直接傳入null即可。第三個參數是一個ContentValues對象,它提供了一系列的put()方法重載,用於向ContentValues中添加數據,只需要將表中的每個列名以及相應的待添加數據傳入即可。
例子:

            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中也是提供了一個非常好用的update()方法用於對數據進行更新,這個方法接收四個參數,第一個參數和insert()方法一樣,也是表名,在這裡指定去更新哪張表裡的數據。第二個參數是ContentValues對象,要把更新數據在這裡組裝進去。第三、第四個參數用於去約束更新某一行或某幾行中的數據,不指定的話默認就是更新所有行。
例子:

            SQLiteDatabase db = dbHelper.getWritableDatabase();
            ContentValues values = new ContentValues();
            values.put("price", 10.99);
    db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" });

這裡在更新數據按鈕的點擊事件裡面構建了一個ContentValues對象,並且只給它指定了一組數據,說明我們只是想把價格這一列的數據更新成10.99。然後調用了SQLiteDatabase的update()方法去執行具體的更新操作,可以看到,這裡使用了第三、第四個參數來指定具體更新哪幾行。第三個參數對應的是SQL語句的where部分,表示去更新所有name等於?的行,而?是一個占位符,可以通過第四個參數提供的一個字符串數組為第三個參數中的每個占位符指定相應的內容。因此上述代碼想表達的意圖就是,將名字是The Da Vinci Code的這本書的價格改成10.99。

刪除數據

SQLiteDatabase中提供了一個delete()方法專門用於刪除數據,這個方法接收三個參數,第一個參數仍然是表名,這個已經沒什麼好說的了,第二、第三個參數又是用於去約束刪除某一行或某幾行的數據,不指定的話默認就是刪除所有行。
例子:

       SQLiteDatabase db = dbHelper.getWritableDatabase();
       db.delete("Book", "page s > ?", new String[] { "500" });    

查詢數據

我們都知道SQL的全稱是Structured Query Language,翻譯成中文就是結構化查詢語言。它的大部功能都是體現在“查”這個字上的,而“增刪改”只是其中的一小部分功能。
SQLiteDatabase中還提供了一個query()方法用於對數據進行查詢。這個方法的參數非常復雜,最短的一個方法重載也需要傳入七個參數。那我們就先來看一下這七個參數各自的含義吧,第一個參數不用說,當然還是表名,表示我們希望從哪張表中查詢數據。第二個參數用於指定去查詢哪幾列,如果不指定則默認查詢所有列。第三、第四個參數用於去約束查詢某一行或某幾行的數據,不指定則默認是查詢所有行的數據。第五個參數用於指定需要去group by的列,不指定則表示不對查詢結果進行group by操作。第六個參數用於對group by之後的數據進行進一步的過濾,不指定則表示不進行過濾。第七個參數用於指定查詢結果的排序方式,不指定則表示使用默認的排序方式。更多詳細的內容可以參考下表。其他幾個query()方法的重載其實也大同小異,你可以自己去研究一下,這裡就不再進行介紹了。
query()方法參數
對應SQL部分
描述
table
from table_name
指定查詢的表名
columns
select column1, column2
指定查詢的列名
selection
where column = value
指定where的約束條件
selectionArgs-為where中的占位符提供具體的值
groupBy
group by column
指定需要group by的列
having
having column = value
對group by後的結果進一步約束
orderBy
order by column1, column2
指定查詢結果的排序方式
雖然query()方法的參數非常多,但是不要對它產生畏懼,因為我們不必為每條查詢語句都指定上所有的參數,多數情況下只需要傳入少數幾個參數就可以完成查詢操作了。調用query()方法後會返回一個Cursor對象,查詢到的所有數據都將從這個對象中取出。
例子:

           SQLiteDatabase db = dbHelper.getWritableDatabase();
            // 查詢Book表中所有的數據
            Cursor cursor = db.query("Book", null, null, null, null, null, null);
            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();

可以看到,我們首先在查詢按鈕的點擊事件裡面調用了SQLiteDatabase的query()方法去查詢數據。這裡的query()方法非常簡單,只是使用了第一個參數指明去查詢Book表,後面的參數全部為null。這就表示希望查詢這張表中的所有數據,雖然這張表中目前只剩下一條數據了。查詢完之後就得到了一個Cursor對象,接著我們調用它的moveToFirst()方法將數據的指針移動到第一行的位置,然後進入了一個循環當中,去遍歷查詢到的每一行數據。在這個循環中可以通過Cursor的getColumnIndex()方法獲取到某一列在表中對應的位置索引,然後將這個索引傳入到相應的取值方法中,就可以得到從數據庫中讀取到的數據了。接著我們使用Log的方式將取出的數據打印出來,借此來檢查一下讀取工作有沒有成功完成。最後別忘了調用close()方法來關閉Cursor。

使用SQL操作數據庫

直接使用SQL來完成前面幾小節中學過的CRUD操作:
添加數據的方法如下:

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);

可以看到,除了查詢數據的時候調用的是SQLiteDatabase的rawQuery()方法,其他的操作都是調用的execSQL()方法。
使用事務
SQLite數據庫是支持事務的,事務的特性可以保證讓某一系列的操作要麼全部完成,要麼一個都不會完成。那麼在什麼情況下才需要使用事務呢?想象以下場景,比如你正在進行一次轉賬操作,銀行會將轉賬的金額先從你的賬戶中扣除,然後再向收款方的賬戶中添加等量的金額。看上去好像沒什麼問題吧?可是,如果當你賬戶中的金額剛剛被扣除,這時由於一些異常原因導致對方收款失敗,這一部分錢就憑空消失了!當然銀行肯定已經充分考慮到了這種情況,它會保證扣錢和收款的操作要麼一起成功,要麼都不會成功,而使用的技術當然就是事務了。
例子:

           Database db = dbHelper.getWritableDatabase();
            db.beginTransaction(); // 開啟事務
            try {
                db.delete("Book", null, null);
                if (true) {
                    // 在這裡手動拋出一個異常,讓事務失敗
                    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(); // 結束事務
            }

上述代碼就是Android中事務的標准用法,首先調用SQLiteDatabase的beginTransaction()方法來開啟一個事務,然後在一個異常捕獲的代碼塊中去執行具體的數據庫操作,當所有的操作都完成之後,調用setTransactionSuccessful()表示事務已經執行成功了,最後在finally代碼塊中調用endTransaction()來結束事務。注意觀察,我們在刪除舊數據的操作完成後手動拋出了一個NullPointerException,這樣添加新數據的代碼就執行不到了。不過由於事務的存在,中途出現異常會導致事務的失敗,此時舊數據應該是刪除不掉的。
升級數據庫的最佳寫法
之前我們學習的升級數據庫的方式是非常粗暴的,為了保證數據庫中的表是最新的,我們只是簡單地在onUpgrade()方法中刪除掉了當前所有的表,然後強制重新執行了一遍onCreate()方法。這種方式在產品的開發階段確實可以用,但是當產品真正上線了之後就絕對不行了。想象以下場景,比如你編寫的某個應用已經成功上線,並且還擁有了不錯的下載量。現在由於添加新功能的原因,使得數據庫也需要一起升級,然後用戶更新了這個版本之後發現以前程序中存儲的本地數據全部丟失了!那麼很遺憾,你的用戶群體可能已經流失一大半了。
聽起來好像挺恐怖的樣子,難道說在產品發布出去之後還不能升級數據庫了?當然不是,其實只需要進行一些合理的控制,就可以保證在升級數據庫的時候數據並不會丟失了。
下面我們就來學習一下如何實現這樣的功能,你已經知道,每一個數據庫版本都會對應一個版本號,當指定的數據庫版本號大於當前數據庫版本號的時候,就會進入到 onUpgrade()方法中去執行更新操作。這裡需要為每一個版本號賦予它各自改變的內容,然後在 onUpgrade()方法中對當前數據庫的版本號進行判斷,再執行相應的改變就可以了。
例子:

@Override
    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的,為什麼要這麼做呢?這是為了保證在跨版本升級的時候,每一次的數據庫修改都能被全部執行到。比如用戶當前是從第二版程序升級到第三版程序的,那麼case 2中的邏輯就會執行。而如果用戶是直接從第一版程序升級到第三版程序的,那麼case 1和case 2中的邏輯都會執行。使用這種方式來維護數據庫的升級,不管版本怎樣更新,都可以保證數據庫的表結構是最新的,而且表中的數據也完全不會丟失了。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved