Android學習筆記:SQLite數據庫開源庫LitePal的基本使用方法

通過項目實踐,來熟悉利用開源庫LitePal來操作SQLite數據庫的基本使用方法。

一、LitePal開源庫

1、簡介

(1)、LitePal:一款開源的Android數據庫框架,它採用了對象關係映射(ORM)模式,將平時開發最常用的一些數據庫功能進行了封裝,從而使得開發者不用編寫一行SQL語句就可以完成各種建表、増刪改查的操作。並且LitePal很“輕”,jar包大小不到100k,近乎零配置,這一點和Hibernate這類的框架有很大區別。目前,LitePal的源碼已經託管到了GitHub上。地址:https://github.com/LitePalFramework/LitePal
(2)、對象關係映射:Object Relational Mapping,簡稱ORM。是通過使用描述對象和數據庫之間映射的元數據,將面嚮對象語言程序中的對象自動持久化到關係數據庫中。本質上就是將數據從一種形式轉換到另外一種形式。 簡單的說,就是將面向關係的數據庫和我們使用的面向對象的語言建立一種映射關係。

2、配置

原來需要下載源碼或者Jar包纔可以使用,現在LitePal開源庫項目已經提交到了jcenter上,我們只需要在app/build.grade文件中聲明該開源庫的引用。
新建項目,LitePalTest,以下所有關於目錄的說明,均在project模式的目錄結構下。
(1)、編輯app/build.grade文件,在dependencies閉包中添加以下內容:
dependencies {
    compile 'org.litepal.android:core:1.6.1'
}
編輯完成後,點擊頁面上方的Sync now來同步。其中,1.6.1是版本號,最新版本號信息可以到LitePal項目主頁去查看。
(2)、配置litepal.xml。
  右擊app/src/main目錄,New -> Directory,新建一個assets目錄,在該目錄下,New -> File,輸入litepal.xml,創建XML文件。並編輯以下內容:
<?xml version="1.0" encoding="utf-8"?>
<litepal>

    <dbname value="BookStore" />

    <version value="1" />

    <list>

    </list>

</litepal>
其中,dbname是數據庫名,我們沿用上一篇關於SQLiteDatabase操作SQLite數據所使用的案例,version是數據庫的版本號,list標籤指定映射模型。
(3)、配置LitePalApplication。
修改AndroidManifest.xml文件,添加以下內容:
<manifest>
    <application
        android:name="org.litepal.LitePalApplication"
        ...
    >
        ...
    </application>
</manifest>
當然,如果你使用了自己的Application,如下所示:
public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        LitePal.initialize(this);
    }
    ...
}
在配置AndroidManifest.xml文件時,則需要按如下所示配置:
<manifest>
    <application
        android:name="com.example.MyApplication"
        ...
    >
        ...
    </application>
</manifest>
經過以上三步配置之後,就可以開始使用LitePal了。

3、創建數據庫

繼續沿用上一篇案例的佈局方案,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/create_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="創建"
        />

    <Button
        android:id="@+id/add_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="添加"
        />

    <Button
        android:id="@+id/update_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="更新"
        />

    <Button
        android:id="@+id/delete_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="刪除"
        />

    <Button
        android:id="@+id/query_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="查詢"
        />

</LinearLayout>
(1)、定義Book類。
package com.my.litepaltest;

public class Book {
    private int id;         //主鍵,可定義可不定義,會自動生成。
    private String author;  //作者
    private double price;   //價格
    private int pages;      //頁數
    private String name;    //書名

    //自動生成的getter和setter方法,Alt + Insert
    
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getPages() {
        return pages;
    }

    public void setPages(int pages) {
        this.pages = pages;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
快速生成getter和setter方法快捷鍵:Alt + Insert
這個Book類就對應的數據庫中的Book表。
(2)、將Book類添加到映射模型中。
修改litepal.xml文件,在list標籤下添加以下數據:
<list>
    <mapping class = "com.my.litepaltest.Book" />
</list>
mapping標籤就是用來聲明我們配置的映射類型,要使用完整的類名。
(3)、修改MainActivity中的代碼:
package com.my.litepaltest;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import org.litepal.LitePal;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button createDatabase = (Button)findViewById(R.id.create_database);
        Button addData = (Button)findViewById(R.id.add_data);
        Button updateData = (Button)findViewById(R.id.update_data);
        Button deleteData = (Button)findViewById(R.id.delete_data);
        Button queryData = (Button)findViewById(R.id.query_data);

        //更新按鈕點擊事件
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LitePal.getDatabase();  //打開或創建數據庫
            }
        });

    }
}
運行程序,點擊創建按鈕:

使用adb調試工具,查看數據庫是否已經創建。

可以看到數據庫已存在,Book也已經建立,還可以查看建表語句:
可以看到建表語句是常規的建表語句,LitePal做了一系列的封裝。

4、升級數據庫

在使用SQLiteOpenHelper幫助類操作數據庫時,升級數據庫都是採用DROP語句,將原來的表drop掉在重新創建,雖然可以通過複雜的邏輯來控制原來的表裏的數據不被刪除,但是維護成本很高。LitePal採用了更加強大的升級數據庫方式,無需刪除原表,只需要修改、版本號加一兩個步驟。
例:在Book表中新增一項press(出版社)列,並再增加一個新的表:Category(圖書分類表)。
(1)、修改Book類代碼:
public class Book {
    ...
    private String press;   //出版社
	...
    public String getPress() {
        return press;
    }

    public void setPress(String press) {
        this.press = press;
    }
}
(2)、新建Category類
package com.my.litepaltest;

public class Category {
    private int id; 
    private String categoryName;    //分類名
    private int categoryCode;       //分類代碼

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    public int getCategoryCode() {
        return categoryCode;
    }

    public void setCategoryCode(int categoryCode) {
        this.categoryCode = categoryCode;
    }
}
(3)、將Category類添加到映射模型中,更新數據庫一定要記得將版本號加一。
修改litepal.xml文件:
<litepal>

    ...

    <version value="2" />

    <list>
        ...
        <mapping class = "com.my.litepaltest.Category" />
    </list>

</litepal>
運行程序,點擊創建按鈕,然後查看建表語句,檢查是否更新。

數據表已成功創建。

5、添加數據

使用LitePal添加數據只需要將模型類的實例創建出來後,設置好數據,調用save()方法就可以了。
另外,涉及到LitePal的CURD操作時,模型類必須繼承DataSupport類纔可以。
(1)、修改Book類。
public class Book extends DataSupport{
	...
}
(2)、修改MainActivity中的代碼,在createDatabase的點擊事件下新增一個addData的點擊事件。
    //添加按鈕點擊事件
    addData.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Book book = new Book();
            book.setName("The Da Vinci Code");
            book.setAuthor("Dan Brown");
            book.setPages(454);
            book.setPrice(16.96);
            book.setPress("Unknown");
            book.save();
        }
    });
save()方法在Book類中並不存在,之所以能使用是因爲他是從DataSupport類中繼承來的。作用就是添加剛剛保存好的數據。
運行程序,點擊添加按鈕,然後查看Book表中的數據。

可以看到剛剛設置的數據已經保存到了數據庫中。

6、更新數據

更新數據有很多種方式(API接口很多),相對於添加數據來說更復雜一點。對於LitePal來說,它只會對已存儲的對象重新設值。
已存儲的對象:LitePal通過modle.isSaved()方法來判斷該對象是否已存儲。返回值爲true代表已存儲,false代表未存儲。
modle.isSaved()返回true的兩種情況:
(1)、該對象調用過modle.save()來添加數據了。
(2)、通過LitePal的API查詢到的對象。
下面介紹兩種更新數據的兩種方式:
(1)、對剛剛添加的數據進行更新。
修改MainActivity的代碼,在addData的點擊事件下,新增一個updateData的點擊事件:
public class MainActivity extends AppCompatActivity {

		...

        //更新數據的點擊事件
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Book book = new Book();
                book.setName("The Lost Symbol");
                book.setAuthor("Dan Brown");
                book.setPages(510);
                book.setPrice(19.95);
                book.setPress("Unknown");
                book.save();
                book.setPrice(10.99);   //對剛纔更新的數據重新設值
                book.save();            //調用save()方法更新數據
            }
        });

    }
}
運行程序,然後點擊更新按鈕,查看Book表中的數據。

可以看到,原本添加的數據是19.95,更新後變成了10.99.
(2)、更靈活的更新方式,updateAll()方法。
updateAll()方法是一種約束式更新,它可以利用約束語句對一行或幾行數據進行更新,不添加約束即對該表內的所有數據進行更新。
更改updateData點擊事件裏的內容:
    //更新數據的點擊事件
    updateData.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
//            Book book = new Book();
//            book.setName("The Lost Symbol");
//            book.setAuthor("Dan Brown");
//            book.setPages(510);
//            book.setPrice(19.95);
//            book.setPress("Unknown");
//            book.save();
//            book.setPrice(10.99);   //對剛纔更新的數據重新設值
//            book.save();            //調用save()方法更新數據

            Book book = new Book();
            book.setPrice(14.95);      //設置新的價格
            book.setPress("Anchor");   //設置新的出版社
            //利用約束語句,將書名爲The Lost Symbol和作者爲Dan Brown的圖書價格、出版社更新
            book.updateAll("name = ? and author = ?","The Lost Symbol","Dan Brown");

        }
    });
運行程序,點擊更新按鈕,查看Book表中的數據:

數據庫中的數據已經按照程序預期進行了更新。
注:
①、約束條件的連接符號只能用 and 進行連接,不能使用 & 符號。
②、對某字段進行恢復成默認值時(Java的數據類型都有默認值,如布爾類型的默認值是false),不可以使用setXXX()方法進行設置,只能使用setToDefault()方法。例如:
Book book = new Book();
book.setToDefault("pages");
book.updateAll();
上述代碼就是對 pages 字段的值進行恢復默認值。若不添加約束條件,則對Book表的所有 pages 字段均有效。

7、刪除數據

LitePal刪除數據的方式主要有兩種,一種是對已存儲對象的刪除操作,調用model.delete()方法。另一種是更加靈活的約束式刪除方式。
修改MainActivity代碼,在updateData點擊事件的下面添加deleteData的點擊事件:
public class MainActivity extends AppCompatActivity {

		...

        //刪除數據的點擊事件
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //刪除Book表中價格大於 15 的書籍
                DataSupport.deleteAll(Book.class,"price > ?","15");
            }
        });

    }
}
運行程序,點擊刪除按鈕,查看Book表中的數據:

對比上一次的查詢結果,價格大於15的書籍已經被刪除。
注:
①:不再是創建Book類實例進行操作,而是調用DataSupport類的deleteAll()方法進行刪除操作。
②:deleteAll()方法若不指定約束條件,則刪除表內所有數據。

8、查詢數據

數據庫最強大的功能就是查詢,LitePal對查詢方法進行了很多優化,有很多方法可供選擇。
修改MainActivity中的代碼,在deleteData的點擊事件下新增一個queryData點擊事件。
public class MainActivity extends AppCompatActivity {

		...
		
        //查詢數據的點擊事件
        queryData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //查詢Book表的所有數據,返回List列表
                List<Book> books = DataSupport.findAll(Book.class);
                for(Book book : books){
                    Log.d("MainActivity", "book name is " + book.getName());
                    Log.d("MainActivity", "book author is " + book.getAuthor());
                    Log.d("MainActivity", "book pages is " + book.getPages());
                    Log.d("MainActivity", "book prices is " + book.getPrice());
                    Log.d("MainActivity", "book press is " + book.getPress());
                }
            }
        });

    }
}
運行程序,點擊查詢按鈕,查看Logcat輸出:
數據庫中僅剩的一條數據的詳細信息已經被打印了出來。
注:
①:不再是創建Book類實例進行操作,而是調用DataSupport類的findAll()方法進行刪除操作。
②:findAll()方法返回的是一個List列表。
③:findAll()方法若不指定約束條件,則返回表內所有數據

更多的LitePal查詢方式:
(1)、查詢Book表的第一條數據
Book firstBook = DataSupport.findFirst(Book.class);
(2)、查詢Book表的最後一條數據
Book lastBook = DataSupport.findLast(Book.class);
(3)、select()方法用於指定查詢某幾列的數據,對應SQL的select關鍵字,例如只查詢name和author兩列的數據:
List<Book> books = DataSupport.select("name","author").find(Book.class);
(4)、where()方法用於指定查詢的約束條件,對應SQL的where關鍵字,例如只查詢頁數大於400的書籍:
List<Book> books = DataSupport.where("pages > ?","400").find(Book.class);
(5)、order()方法用於指定結果的排序方式,對應SQL的order by關鍵字,例如將查詢結果按書價從高到低排序:
List<Book> books = DataSupport.order("price desc").find(Book.class);
其中desc代表降序,asc或者不寫表示升序。
(6)、limit()方法用於指定查詢結果的數量,例如查詢表中的前三條數據:
List<Book> books = DataSupport.limit(3).find(Book.class);
(7)、offset()用於指定查詢結果的偏移量,例如查詢表中的第2、3、4條數據:
List<Book> books = DataSupport.limit(3).offset(1).find(Book.class);
limit()和offset()方法共同對應了SQL的limit關鍵字。
(8)、更靈活的查詢方式,將上述5種方法進行任意的連綴組合,完成一個複雜的查詢:
List<Book> books = DataSupport.select("name","author","pages")
							  .where("pages > ?","400")
							  .order("pages")
							  .limit(10)
							  .offset(10)
							  .find(Book.class);
這段代碼的含義是:查詢10~20行中滿足頁數大於400這個條件的name、author和pages這三列數據,並將查詢結果按頁數的升序排列。
(9)、LitePal仍然支持使用原生的SQL來查詢:
Cursor cursor = DataSupport.findBtSQL("select * from Book where pages > ? and price < ?","400","200");

9、異步操作

默認情況下,每個數據庫操作都在主線程上,如果你的操作可能要花費大量的時間,例如保存或查詢大量數據,就會使用到異步操作。LitePal支持CURD所有方法的異步操作,若是想從後臺線程中查詢Book表(假設此時Book表裏的數據非常多)中的所有數據,可以使用以下的代碼:
DataSupport.findAllAsync(Book.class).listen(new FindMultiCallback() {
    @Override
    public <T> void onFinish(List<T> t) {
        List<Book> books = (List<Book>) t;
    }
});
如果使用findAllAsync()而不是findAll(),需要添加一個listen()方法,一旦操作完成,查詢結果將在onFinish()方法中被回調。
book.setName("The Da Vinci Code");
book.setAuthor("Dan Brown");
book.setPages(454);
book.setPrice(16.96);
book.setPress("Unknown");
book.saveAsync().listen(new saveCallback(){
	@Override
    public void onFinish(boolean success) {
		...
    }
});
如果使用saveAsync()而不是save()方法,將會在後臺向數據庫中添加數據,保存結果將在onFinish()方法中被回調。

10、多個數據庫

如果應用程序需要多個數據庫,LitePal同樣支持,你可以在程序運行時創建多個數據庫。
例如在運行時,創建一個Person數據庫,包含姓名name、年齡Age和性別Sex三個字段:
LitePalDB litePalDB = new LitePalDB("Person", 1);
litePalDB.addClassName(Name.class.getName());
litePalDB.addClassName(Age.class.getName());
litePalDB.addClassName(Sex.class.getName());
LitePal.use(litePalDB); 	//創建數據庫
如果想新建一個數據庫,但是這個數據庫的配置和litepal.xml一樣,可以使用以下代碼:
LitePalDB litePalDB = LitePalDB.fromDefault("BookStore");
LitePal.use(litePalDB); 	//使用litepal.xml創建一個新數據庫
也可以隨時返回默認的數據庫:
LitePal.useDefault(); 	//返回默認數據庫
也可以通過指定數據庫的名字來刪除它:
LitePal.deleteDatabase("BookStore"); 	//刪除數據庫

對比使用SQLiteDatabase來操作SQLite數據庫,LitePal在使用上會更加強大。



本文總結參考自郭神(郭霖)的《第一行代碼 第2版》和GitHub上的源碼說明。
LitePal是郭神開發的開源庫,書中都沒有說明,百度了才知道,真的是低調!!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章