Android數(shù)據(jù)存儲(chǔ)(三)

前面兩篇文章Android數(shù)據(jù)存儲(chǔ)(一)Android數(shù)據(jù)存儲(chǔ)(二)分別使用文件存儲(chǔ)薛训、SharedPreferences的方式來對(duì)數(shù)據(jù)進(jìn)行存儲(chǔ)终娃。這篇主要是講SQLite數(shù)據(jù)庫(kù)的創(chuàng)建获黔,表的創(chuàng)建勃蜘,以及數(shù)據(jù)的增刪改查罐氨。為了保持連貫性,我就把全部?jī)?nèi)容都在這篇文章中講了米间,所以內(nèi)容稍微有點(diǎn)長(zhǎng)强品。文中使用ADB工具來查看數(shù)據(jù)庫(kù)中的數(shù)據(jù),如果沒有安裝ADB調(diào)試工具的話屈糊,請(qǐng)自行安裝的榛。完整代碼在:https://github.com/AD-feiben/DatabaseTest

為什么要使用SQLite

文件存儲(chǔ)和SharedPreferences存儲(chǔ)只適用于去保存一些簡(jiǎn)單的數(shù)據(jù)和鍵值對(duì),當(dāng)需要存儲(chǔ)大量復(fù)雜的關(guān)系型數(shù)據(jù)的時(shí)候逻锐,這兩種存儲(chǔ)方式就很難應(yīng)付了夫晌。

程序界面

1.創(chuàng)建數(shù)據(jù)庫(kù)

Android為了讓我們更加方便的管理數(shù)據(jù)庫(kù),專門提供了一個(gè)SQLiteOpenHelper幫助類昧诱,借助這個(gè)類可以非常簡(jiǎn)單地對(duì)數(shù)據(jù)庫(kù)進(jìn)行創(chuàng)建和升級(jí)晓淀。SQLiteOpenHelper是一個(gè)抽象類,我們要使用的話需要先創(chuàng)建一個(gè)自己的幫助類去繼承它鳄哭,而且必須在我們的幫助類重寫onCreate()和onUpgrade()這兩個(gè)方法要糊,然后分別在這兩個(gè)方法中去實(shí)現(xiàn)創(chuàng)建、升級(jí)數(shù)據(jù)庫(kù)的邏輯妆丘。

SQLiteOpenHelper有兩個(gè)非常重要的實(shí)例方法锄俄,getReadableDatabase()和getWritableDatabase()。這兩個(gè)方法都可以創(chuàng)建或者打開一個(gè)現(xiàn)有的數(shù)據(jù)庫(kù)勺拣,并返回一個(gè)可以數(shù)據(jù)庫(kù)進(jìn)行讀寫操作的對(duì)象奶赠。不同的是,當(dāng)數(shù)據(jù)庫(kù)不可寫入的時(shí)候(如磁盤空間已滿)getReadableDatabase()方法返回的對(duì)象將以只讀的方式去打開數(shù)據(jù)庫(kù)药有,而 getWritableDatabase()方法則將出現(xiàn)異常毅戈。

SQLiteOpenHelper有兩個(gè)構(gòu)造方法可以重寫,一般使用參數(shù)少一點(diǎn)的那個(gè)愤惰,這個(gè)構(gòu)造方法有四個(gè)參數(shù)苇经,第一個(gè)是Context,第二個(gè)是數(shù)據(jù)庫(kù)名宦言,第三個(gè)是允許我們?cè)诓樵償?shù)據(jù)的時(shí)候返回一個(gè)自定義的 Cursor扇单,一般傳入null,第四個(gè)表示當(dāng)前數(shù)據(jù)庫(kù)的版本號(hào)奠旺,用于升級(jí)數(shù)據(jù)庫(kù)蜘澜。實(shí)例化SQLiteOpenHelper對(duì)象后施流,調(diào)用它的getReadableDatabase()或getWritableDatabase()方法就能創(chuàng)建出數(shù)據(jù)庫(kù)了,數(shù)據(jù)庫(kù)文件存放于/data/data/<package name>/databases/目錄下鄙信。

在新建項(xiàng)目之前先來看一下SQL的建表語句

create table Book(id integer primary key autoincrement,name text,author text,pages integer,price real)

SQLite的數(shù)據(jù)類型比較簡(jiǎn)單瞪醋,integer表示整形,real表示浮點(diǎn)型装诡,text表示文本類型银受,blob表示二進(jìn)制類型。另外上述建表語句還使用primary key將id設(shè)為主鍵鸦采,autoincrement將id列設(shè)為自動(dòng)增長(zhǎng)的蚓土。

接下來新建一個(gè)DatabaseTest項(xiàng)目來看看如何闖創(chuàng)建數(shù)據(jù)庫(kù)吧。首先在布局中放一個(gè)Button用來創(chuàng)建數(shù)據(jù)庫(kù)赖淤,這部分就不展示出來了。然后創(chuàng)建MyDatabaseHelper類繼承自SQLiteOpenHelper谅河,代碼如下:

public class MyDatabaseHelper extends SQLiteOpenHelper {   
 
    private static final String CREATE_BOOK = "create table Book(" +            
            "id integer primary key autoincrement," +            
            "name text," +            
            "author text," +            
            "pages integer," +            
            "price real)";    
    private Context context;    

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {        
        super(context, name, factory, version);        
        this.context = context;    
    }    
    @Override    
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);            
        Toast.makeText(context, "Database Created succeeded", Toast.LENGTH_SHORT).show();    
    }    

    @Override    
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        

    }
}

首先把建表語句定義為字符串常量咱旱,然后在onCreate()方法中調(diào)用SQLiteDatabase的execSQL()方法來執(zhí)行這條建表語句完成建表。然后在MainActivity的Button監(jiān)聽事件來完成數(shù)據(jù)庫(kù)的創(chuàng)建绷耍,findViewById和為Button設(shè)置鍵監(jiān)聽器的部分就不寫了吐限,代碼如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private MyDatabaseHelper databaseHelper;
    private SQLiteDatabase db;

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

        databaseHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);    
        ……
    }

    @Override
    public void onClick(View v) {    
      switch (v.getId()) {        
        case R.id.create_database:            
            db = databaseHelper.getWritableDatabase();            
            break;
        default:        
            break;
        }
    }
}

運(yùn)行一下程序,創(chuàng)建完數(shù)據(jù)庫(kù)之后就會(huì)彈出一個(gè)Toast來提醒褂始。接下來使用ADB來驗(yàn)證數(shù)據(jù)庫(kù)BookStore.db以及Book表的創(chuàng)建诸典。

首先使用adb shell進(jìn)入設(shè)備,然后進(jìn)入/data/data/<package name>/databases/目錄崎苗,再用ls查看目錄下的文件狐粱,可以看到BookStore.db數(shù)據(jù)庫(kù)已經(jīng)創(chuàng)建出來了,另一個(gè)BookStore.db-journal 則是為了讓數(shù)據(jù)庫(kù)能夠支持事務(wù)而產(chǎn)生的臨時(shí)日志文件胆数,可以不用管它肌蜻。

然后用sqlite3 BookStore.db打開BookStore.db數(shù)據(jù)庫(kù)(注意數(shù)據(jù)庫(kù)名字不要打錯(cuò)了,如果你發(fā)現(xiàn)數(shù)據(jù)庫(kù)里沒有Book表必尼,很有可能就是你打錯(cuò)了數(shù)據(jù)庫(kù)的名字蒋搜,這個(gè)時(shí)候用.exit或者.quit命令就可以關(guān)閉這個(gè)錯(cuò)的數(shù)據(jù)庫(kù)了,再用rm 數(shù)據(jù)庫(kù)名就可以刪掉錯(cuò)誤的數(shù)據(jù)庫(kù)了)判莉。

然后用.table命令(注意“.”)就可以看到該數(shù)據(jù)庫(kù)下的表了豆挽。android_metadata 表是每個(gè)數(shù)據(jù)庫(kù)中都會(huì)自動(dòng)生成的,這個(gè)也不用管它券盅。這里還可以通過**.schema **命令來查看它們的建表語句帮哈。

2.在數(shù)據(jù)庫(kù)中新建一個(gè)表

如果要新建一個(gè)表的話,與前面的方法一樣渗饮,首先需要在MyDatabaseHelper類把建表語句定義為字符串常量但汞,然后在onCreate中完成建表宿刮。

public class MyDatabaseHelper extends SQLiteOpenHelper {    
    ……
    private static final String CREATE_CATEGORY = "create table Category(" +            
        "id integer primary key autoincrement," +            
        "category_name text," +            
        "category_cade integer)";    
    ……
    @Override    
    public void onCreate(SQLiteDatabase db) {        
        db.execSQL(CREATE_BOOK);        
        db.execSQL(CREATE_CATEGORY);        
        Toast.makeText(context, "Database Created succeeded", Toast.LENGTH_SHORT).show();    
}   

    @Override    
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        

    }
}

重新運(yùn)行一下程序點(diǎn)擊Button可以發(fā)現(xiàn)并不會(huì)有Toast彈出來,用ADB工具也差看不到Category這張表私蕾。原因就在SQLiteOpenHelper的getWritableDatabase()只有數(shù)據(jù)庫(kù)不存在的時(shí)候才會(huì)創(chuàng)建數(shù)據(jù)庫(kù)并調(diào)用MyDatabaseHelper的onCreate方法僵缺,現(xiàn)在數(shù)據(jù)庫(kù)已經(jīng)存在,所以無論我們?cè)趺袋c(diǎn)“Create Database”都不會(huì)創(chuàng)建一個(gè)新的數(shù)據(jù)庫(kù)〔劝龋現(xiàn)在只有卸載這個(gè)程序或者利用ADB的rm BookStore.db命令將數(shù)據(jù)庫(kù)刪除后再創(chuàng)建新的數(shù)據(jù)庫(kù)才會(huì)有Category表磕潮。

以上兩種辦法都有點(diǎn)暴力,需要上線的APP肯定不能用這樣的方法容贝,有沒有其他的方法不這么暴力的呢自脯?答案肯定是有的,利用升級(jí)這個(gè)辦法我們就可以實(shí)現(xiàn)給數(shù)據(jù)庫(kù)添加一張新表或者其他的操作斤富。然后修改MyDatabaseHelper的onUpgrade方法膏潮。因?yàn)樯?jí)數(shù)據(jù)庫(kù)時(shí)就會(huì)調(diào)用這個(gè)方法。

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    
    db.execSQL("drop table if exists Book");    
    db.execSQL("drop table if exists Category");    
    onCreate(db);
}

可以看到這里執(zhí)行了兩條drop語句满力,當(dāng)Book表或Category表已經(jīng)存在的話就會(huì)把這兩張表刪掉焕参,然后再調(diào)用onCreate()方法重新建表。只所以在重新建表之前要?jiǎng)h掉原來的表油额,是因?yàn)樵趧?chuàng)建表時(shí)如果已經(jīng)存在叠纷,那么就會(huì)直接報(bào)錯(cuò)。接下來修改MainActivity的代碼潦嘶。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    ……
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ……
        databaseHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
    }
    ……
}

databaseHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2)最后的版本號(hào)要比原來的版本號(hào)大涩嚣,數(shù)據(jù)庫(kù)才會(huì)進(jìn)行升級(jí)。重新運(yùn)行程序掂僵,再利用ADB工具來查看數(shù)據(jù)庫(kù)里的內(nèi)容航厚。

這次可以看到數(shù)據(jù)庫(kù)升級(jí)之后,Category表也被創(chuàng)建出來了】淳現(xiàn)在數(shù)據(jù)庫(kù)已經(jīng)創(chuàng)建出來了阶淘,也完成了升級(jí),但是Book表和Category表都沒有數(shù)據(jù)互妓,接下來就來看看怎么給Book表添加數(shù)據(jù)溪窒。

3.添加數(shù)據(jù)

通過前面的練習(xí),我們已經(jīng)知道冯勉,調(diào)用SQLiteOpenHelper的getReadableDatabase()或 getWritableDatabase()方法是可以用于創(chuàng)建和升級(jí)數(shù)據(jù)庫(kù)的澈蚌,不僅如此,這兩個(gè)方法還都會(huì)返回一個(gè)SQLiteDatabase對(duì)象灼狰,借助這個(gè)對(duì)象就可以對(duì)數(shù)據(jù)進(jìn)行 CRUD 操作了宛瞄。什么是CRUD操作?C就是Create(添加數(shù)據(jù))交胚;R就是Retrieve(查詢數(shù)據(jù))份汗;U就是Update(更新數(shù)據(jù))盈电;D就是Delete(刪除數(shù)據(jù))。

接下來就先來看看怎么進(jìn)行C操作吧杯活。SQLiteDatabase中提供了一個(gè)insert()方法匆帚,這個(gè)方法就是專門用于添加數(shù)據(jù)的。它接收三個(gè)參數(shù)旁钧,第一個(gè)參數(shù)是表名吸重,我們希望向哪張表里添加數(shù)據(jù),這里就傳入該表的名字歪今。第二個(gè)參數(shù)用于在未指定添加數(shù)據(jù)的情況下給某些可為空的列自動(dòng)賦值 null嚎幸,一般我們用不到這個(gè)功能, 直接傳入 null 即可寄猩。 第三個(gè)參數(shù)是一個(gè)ContentValues 對(duì)象嫉晶, 它提供了一系列的 put()方法重載,用于向ContentValues 中添加數(shù)據(jù)田篇,只需要將表中的每個(gè)列名以及相應(yīng)的待添加數(shù)據(jù)傳入即可车遂。

接下來再布局中加入一個(gè)Insert Data按鈕,在MainActivity中添加監(jiān)聽事件斯辰,代碼如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    ……
    private ContentValues values = new ContentValues();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ……
    }

    @Override
    public void onClick(View v) {    
        switch (v.getId()) {        
            ……
            case R.id.insert_data:    
                db = databaseHelper.getWritableDatabase();  
                values.clear();      
                //第一條數(shù)據(jù)    
                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();    
                //第二條數(shù)據(jù)    
                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);    
                break;
            default:        
                break;
        }
    }
}

首先先實(shí)例化一個(gè)ContentValues對(duì)象,在insert數(shù)據(jù)之前先清空ContentValues的值坡疼,然后把要添加的數(shù)據(jù)放到ContentValues進(jìn)行組裝彬呻,這里并沒有給id那一列賦值,因?yàn)閕d我們已經(jīng)設(shè)置為自動(dòng)增長(zhǎng)的柄瑰,它的值會(huì)在入庫(kù)的時(shí)候自動(dòng)生成闸氮,所以不需要我們手動(dòng)賦值了,最后調(diào)用SQLiteDatabase的insert()方法將數(shù)據(jù)添加到對(duì)應(yīng)的表中教沾。這里實(shí)際上是添加了兩條數(shù)據(jù)蒲跨,因?yàn)檎{(diào)用了兩次insert()方法,并且ContentValues組裝的內(nèi)容也不相同授翻。

接下來運(yùn)行程序或悲,點(diǎn)擊Insert Data按鈕,再利用ADB工具查看效果堪唐。前面的命令都用過了就不過多解釋了巡语,select * from Book;是SQL命令,用來查詢表中的數(shù)據(jù)淮菠,完整的命令格式是“select列名稱from表名稱 where 限定條件”男公,可以選擇要查詢的列中滿足限定條件的數(shù)據(jù)。我們?cè)诹忻Q這里用*代替合陵,說明查詢所有列枢赔,而且不加限定條件就說明我們要查Book表的所有數(shù)據(jù)澄阳。

注意在最后要加上“;”,我就掉進(jìn)過這個(gè)坑中踏拜,好一會(huì)才爬出來碎赢。

可以看到數(shù)據(jù)已經(jīng)成功的條件到了Book表中了,接下來來看一下怎么進(jìn)行U操作吧执隧。

4.更新數(shù)據(jù)

SQLiteDatabase中也是提供了一個(gè)非常好用的update()方法用于對(duì)數(shù)據(jù)進(jìn)行更新揩抡,這個(gè)方法接收四個(gè)參數(shù),第一個(gè)參數(shù)和insert()方法一樣镀琉,也是表名峦嗤,在這里指定去更新哪張表里的數(shù)據(jù)。第二個(gè)參數(shù)是ContentValues對(duì)象屋摔,要把更新數(shù)據(jù)在這里組裝進(jìn)去烁设。第三、第四個(gè)參數(shù)用于去約束更新某一行或某幾行中的數(shù)據(jù)钓试,不指定的話默認(rèn)就是更新所有行装黑。

在布局中加入U(xiǎn)pdata data按鈕,在MainActivity中給它添加監(jiān)聽事件弓熏。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    ……

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ……
    }

    @Override
    public void onClick(View v) {    
        switch (v.getId()) {        
            ……
          case R.id.update_data:    
                db = databaseHelper.getWritableDatabase();    
                values.clear();    
                values.put("price", 10.99);    
                db.update("Book", values, "name = ?", new String[]{"The Da Vinci Code"});    
                break;
            default:        
                break;
        }
    }
}

這里還是使用同一個(gè)ContentValues恋谭,不過這次只放了一個(gè)price的數(shù)據(jù)。然后調(diào)用了SQLiteDatabase的update()方法去執(zhí)行具體的更新操作挽鞠,可以看到疚颊,這里使用了第三、第四個(gè)參數(shù)來指定具體更新哪幾行信认。第三個(gè)參數(shù)對(duì)應(yīng)的是SQL語句的where部分材义,表示去更新所有name等于?的行,而?是一個(gè)占位符嫁赏,可以通過第四個(gè)參數(shù)提供的一個(gè)字符串?dāng)?shù)組為第三個(gè)參數(shù)中的每個(gè)占位符指定相應(yīng)的內(nèi)容其掂。因此上述代碼想表達(dá)的意圖就是,將name為The Da Vinci Code的price改成10.99潦蝇。

運(yùn)行程序點(diǎn)擊Updata data按鈕款熬,通過ADB工具查看效果。


可以看到第一條數(shù)據(jù)也就是name為The Da Vinci Code的這條數(shù)據(jù)的price改為10.99了攘乒。數(shù)據(jù)的更新就到這里华烟,接下來看一下D操作吧。

5.刪除數(shù)據(jù)

刪除數(shù)據(jù)相比前面兩種操作就更加簡(jiǎn)單了持灰,SQLiteDatabase中提供了一個(gè)delete()方法專門用于刪除數(shù)據(jù)盔夜,這個(gè)方法接收三個(gè)參數(shù),第一個(gè)參數(shù)仍然是表名,第二喂链、第三個(gè)參數(shù)又是用于去約束刪除某一行或某幾行的數(shù)據(jù)返十,不指定的話默認(rèn)就是刪除所有行。

添加Delete data 按鈕椭微,然后為其添加監(jiān)聽事件洞坑。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    ……

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ……
    }

    @Override
    public void onClick(View v) {    
        switch (v.getId()) {        
            ……
            case R.id.delete_data:    
                db = databaseHelper.getWritableDatabase();    
                db.delete("Book", "pages>?", new String[]{"500"});    
                break;
            default:        
                break;
        }
    }
}

與更新數(shù)據(jù)一樣,這里也是使用了where來修飾要?jiǎng)h除的行蝇率,將第三個(gè)參數(shù)的值替換第二個(gè)參數(shù)的?占位符迟杂,代碼表達(dá)的意思就是刪除Book表中pages>500的那條數(shù)據(jù)。

運(yùn)行程序點(diǎn)擊Delete data 按鈕本慕,通過ADB工具查看效果排拷。


可以看到pages為510的這條數(shù)據(jù)被刪掉了,只剩下pages為454的這條數(shù)據(jù)锅尘。數(shù)據(jù)的刪除就到這里监氢,接下來看一下R操作吧。

6.查詢數(shù)據(jù)

SQL 的全稱是Structured Query Language藤违,翻譯成中文就是結(jié)構(gòu)化查詢語言浪腐。它的大部功能都是體現(xiàn)在“查”這個(gè)字上的,而“增刪改”只是其中的一小部分功能顿乒。

SQLiteDatabase中還提供了一個(gè)query()方法用于對(duì)數(shù)據(jù)進(jìn)行查詢议街,我將使用兩種查詢方法來做演示。這個(gè)方法的參數(shù)非常復(fù)雜璧榄,最短的一個(gè)方法重載也需要傳入七個(gè)參數(shù)傍睹。先來看一下這七個(gè)參數(shù)各自的含義吧。第一個(gè)參數(shù)不用說犹菱,當(dāng)然還是表名,表示我們希望從哪張表中查詢數(shù)據(jù)吮炕。第二個(gè)參數(shù)用于指定去查詢哪幾列腊脱,如果不指定則默認(rèn)查詢所有列。第三龙亲、第四個(gè)參數(shù)用于去約束查詢某一行或某幾行的數(shù)據(jù)陕凹,不指定則默認(rèn)是查詢所有行的數(shù)據(jù)。第五個(gè)參數(shù)用于指定需要去group by的列鳄炉,不指定則表示不對(duì)查詢結(jié)果進(jìn)行g(shù)roup by操作杜耙。第六個(gè)參數(shù)用于對(duì)group by之后的數(shù)據(jù)進(jìn)行進(jìn)一步的過濾,不指定則表示不進(jìn)行過濾拂盯。第七個(gè)參數(shù)用于指定查詢結(jié)果的排序方式佑女,不指定則表示使用默認(rèn)的排序方式。

第二種方法跟第一種差別不大,我就不這里贅述了团驱,直接在代碼中以注釋的方式來解釋每個(gè)參數(shù)摸吠。

首先添加Query data 按鈕,然后為其添加監(jiān)聽事件嚎花。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    ……
    private String Tag = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ……
    }

    @Override
    public void onClick(View v) {    
        switch (v.getId()) {        
            ……
            case R.id.query_data:                
                db = databaseHelper.getWritableDatabase();                
                /**                 
                * 查詢指定表寸痢,返回一個(gè)Cursor對(duì)象。                 
                * @param table     要查詢的表名紊选。                 
                * @param columns   要查詢的列名啼止,如果傳入null將會(huì)查詢所有的列                 
                * @param selection 指定Where的約束條件,用于約束查詢某一列或某幾列的數(shù)據(jù)兵罢,傳入空將會(huì)返回所有列献烦。                 
                * @param selectionArgs 將selectionArgs值逐個(gè)替換selection中的"?"占位符。                 
                * @param groupBy 控制列分組趣些,傳入null就不進(jìn)行分組                 
                * @param having 對(duì)groupBy之后的數(shù)據(jù)進(jìn)一步過濾仿荆,傳入null則不進(jìn)行過濾                 
                * @param orderBy 對(duì)查詢后的數(shù)據(jù)進(jìn)行排序,傳入null就會(huì)默認(rèn)排序坏平,也可能是無序的拢操。                 
                * @return 返回一個(gè)Cursor對(duì)象                 
                */                
                Cursor cursor = db.query("Book", null, null, null, null, null, null);                


                /**                 
                * @param distinct 傳入true就會(huì)去除重復(fù)的數(shù)據(jù),傳去false則反之舶替。                 
                * @param table The table name to compile the query against.                 
                * @param columns A list of which columns to return. Passing null will                 
                *            return all columns, which is discouraged to prevent reading                 
                *            data from storage that isn't going to be used.                 
                * @param selection A filter declaring which rows to return, formatted as an                 
                *            SQL WHERE clause (excluding the WHERE itself). Passing null                 
                *            will return all rows for the given table.                 
                * @param selectionArgs You may include ?s in selection, which will be                 
                *         replaced by the values from selectionArgs, in order that they                 
                *         appear in the selection. The values will be bound as Strings.                 
                * @param groupBy A filter declaring how to group rows, formatted as an SQL                 
                *            GROUP BY clause (excluding the GROUP BY itself). Passing null                 
                *            will cause the rows to not be grouped.                 
                * @param having A filter declare which row groups to include in the cursor,                 
                *            if row grouping is being used, formatted as an SQL HAVING                 
                *            clause (excluding the HAVING itself). Passing null will cause                 
                *            all row groups to be included, and is required when row                 
                *            grouping is not being used.                 
                * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause                 
                *            (excluding the ORDER BY itself). Passing null will use the                 
                *            default sort order, which may be unordered.                 
                * @param limit 指明返回的rows的數(shù)量令境。                 
                * @return A {@link Cursor} object, which is positioned before the first entry. Note that                 
                * {@link Cursor}s are not synchronized, see the documentation for more details.                 
                * @see Cursor                 
                */
//                Cursor cursor = db.query(true,"Book",new String[]{"name","author","price"},"price<?",new String[]{"15"},null,null,null,null);                

                if (cursor.moveToFirst()) {                    
                    do {                        
                        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(Tag, "book name is " + name);                        
                        Log.d(Tag, "book author is " + author);                        
                        Log.d(Tag, "book pages is " + pages);                        
                        Log.d(Tag, "book price is " + price);                    
                    } while (cursor.moveToNext());                
                }                
                cursor.close();                
                break;
            default:        
                break;
        }
    }
}

在這里我將兩種查詢數(shù)據(jù)的方法都寫在一起,這樣大家容易對(duì)比兩個(gè)方法有什么不同顾瞪,當(dāng)然查詢數(shù)據(jù)的方法不知這兩個(gè)舔庶,而且我給了這兩個(gè)方法的注釋,第一個(gè)方法用的是中文注釋(英文不好陈醒,有弄錯(cuò)的地方希望大神可以指正)惕橙,第二個(gè)方法我用的是源代碼中的注釋,但是有兩個(gè)參數(shù)是第一個(gè)方法中沒有的钉跷,我就用中文注釋了弥鹦。

先注釋掉第二個(gè)方法,來看看第一個(gè)查詢數(shù)據(jù)的結(jié)果是怎么樣的爷辙。在查詢按鈕的點(diǎn)擊事件里面調(diào)用了SQLiteDatabase的query()方法去查詢數(shù)據(jù)彬坏。這里的query()方法非常簡(jiǎn)單,只是使用了第一個(gè)參數(shù)指明去查詢Book表膝晾,后面的參數(shù)全部為null栓始。這就表示希望查詢這張表中的所有數(shù)據(jù),雖然這張表中目前只剩下一條數(shù)據(jù)了血当。查詢完之后就得到了一個(gè)Cursor對(duì)象幻赚,接著我們調(diào)用它的moveToFirst()方法將數(shù)據(jù)的指針移動(dòng)到第一行的位置禀忆,然后進(jìn)入了一個(gè)循環(huán)當(dāng)中,去遍歷查詢到的每一行數(shù)據(jù)坯屿。在這個(gè)循環(huán)中可以通過Cursor的getColumnIndex()方法獲取到某一列在表中對(duì)應(yīng)的位置索引油湖,然后將這個(gè)索引傳入到相應(yīng)的取值方法中,就可以得到從數(shù)據(jù)庫(kù)中讀取到的數(shù)據(jù)了领跛。接著我們使用Log的方式將取出的數(shù)據(jù)打印出來疙挺,借此來檢查一下讀取工作有沒有成功完成挚赊。最后別忘了調(diào)用close()方法來關(guān)閉Cursor。

現(xiàn)在我們的數(shù)據(jù)庫(kù)只有一條數(shù)據(jù),按下Insert data添加多兩條數(shù)據(jù)再按下Query data按鈕來查詢數(shù)據(jù)凭需,看Android Studio的控制臺(tái)輸出就可以知道查詢的結(jié)果了垒探。


不難看出一共是有3條數(shù)據(jù)徙鱼。我們?cè)儆肁DB工具來驗(yàn)證一下是不是3條數(shù)據(jù)复濒。


可以看到也是只有3條數(shù)據(jù),id為2的已經(jīng)被我們給刪除了蒲肋。所以使用SQLiteDatabase的query()來查詢數(shù)據(jù)完全是沒有問題的蘑拯。

接下來看看第二種查詢方法會(huì)得出什么結(jié)果。首先注釋掉第一種方法兜粘,然后再取消注釋第二個(gè)方法申窘,重新run一下。再按下Query data按鈕孔轴,程序居然崩掉了剃法,看一下Log。

這個(gè)異常是非法狀態(tài)異常路鹰,后半句提示我們?cè)谠L問數(shù)據(jù)之前對(duì)指針正確地初始化贷洲。然后MainActivity.java:124跳轉(zhuǎn)到出錯(cuò)的代碼。
可以看到我們?cè)诓樵償?shù)據(jù)的時(shí)候并沒有查詢pages這一列晋柱,但是我們?cè)诤竺媸褂?strong>int pages = cursor.getInt(cursor.getColumnIndex("pages"));從cursor中取出pages的值所以導(dǎo)致程序崩潰优构,將這句代碼以及相應(yīng)的Log注釋掉即可。然后重新運(yùn)行程序雁竞。
可以看到只有一條數(shù)據(jù)钦椭,因?yàn)槲覀兗恿艘粭lprice<15的條件,接下來我們把15改成20浓领,然后運(yùn)行程序,再insert幾條數(shù)據(jù)進(jìn)去势腮。
我們可以從ADB工具看到一共是由9條數(shù)據(jù)的(id=2的被刪掉了)联贩。然后按下Query data按鈕,查看Log捎拯。
只有3條數(shù)據(jù)泪幌,而且沒有pages這一列盲厌。因?yàn)槲覀兊谝粋€(gè)參數(shù)傳進(jìn)了一個(gè)true,所以查詢結(jié)果會(huì)把重復(fù)的部分去除掉祸泪。我們?cè)诘谌齻€(gè)參數(shù)中傳入了new String[]{"name","author","price"}意思就是只查詢name吗浩、author以及price這三列的數(shù)據(jù),所以不會(huì)有pages的結(jié)果没隘。

在Android中同樣可以使用SQL操作數(shù)據(jù)庫(kù)懂扼,例如:

因?yàn)槲恼缕^長(zhǎng),就不再過多介紹了右蒲,有興趣的話可以去查找SQL的相關(guān)資料學(xué)習(xí)阀湿。

如果文章對(duì)你有所幫助,那么請(qǐng)您點(diǎn)一下?
由于本人水平有限瑰妄,如有錯(cuò)誤陷嘴,歡迎大家指正。如果你在操作過程中發(fā)現(xiàn)一些沒有講到的錯(cuò)誤或者問題间坐,歡迎在評(píng)論留言灾挨,一起探討,共同學(xué)習(xí)進(jìn)步竹宋!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末劳澄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子逝撬,更是在濱河造成了極大的恐慌浴骂,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宪潮,死亡現(xiàn)場(chǎng)離奇詭異溯警,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)狡相,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門梯轻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人尽棕,你說我怎么就攤上這事喳挑。” “怎么了滔悉?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵伊诵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我回官,道長(zhǎng)曹宴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任歉提,我火速辦了婚禮笛坦,結(jié)果婚禮上区转,老公的妹妹穿的比我還像新娘。我一直安慰自己版扩,他們只是感情好废离,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著礁芦,像睡著了一般蜻韭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宴偿,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天湘捎,我揣著相機(jī)與錄音,去河邊找鬼窄刘。 笑死窥妇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的娩践。 我是一名探鬼主播活翩,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼翻伺!你這毒婦竟也來了材泄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤吨岭,失蹤者是張志新(化名)和其女友劉穎拉宗,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辣辫,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旦事,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了急灭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姐浮。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖葬馋,靈堂內(nèi)的尸體忽然破棺而出卖鲤,到底是詐尸還是另有隱情,我是刑警寧澤畴嘶,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布蛋逾,位于F島的核電站,受9級(jí)特大地震影響窗悯,放射性物質(zhì)發(fā)生泄漏区匣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一蟀瞧、第九天 我趴在偏房一處隱蔽的房頂上張望沉颂。 院中可真熱鬧,春花似錦悦污、人聲如沸铸屉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彻坛。三九已至,卻和暖如春踏枣,著一層夾襖步出監(jiān)牢的瞬間昌屉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工茵瀑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留间驮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓马昨,卻偏偏與公主長(zhǎng)得像竞帽,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鸿捧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容