常常聽到已經工做的程序員說天天的工做很無聊,老是一些CURD操做,沒什麼技術含量,對,今天咱們就要勇敢的探索一下這所謂的「無聊工做」--CURD,並想辦法讓它有趣起來。所謂的CURD,其實就是數據庫的基本操做,C表明create,U表明update,R表明read,D則表明delete。寫事後臺腳本的朋友對這個應該很熟悉,你就能夠隨便翻翻啦,而不太瞭解數據庫操做的朋友,我在這裏拋磚引玉,講一下怎麼將內存中的數據保存到本地數據庫中,您看完後能夠更加深刻的去尋找一些資料學習,千萬要記得無論別人說什麼無聊或者沒有技術含量,咱們仍是要一步一個腳印,堅持敲下去!java
前面說了咱們要把這簡單的操做講的有趣些,那我就玩點套路,不直接講API,先來看一個類:android
package com.aristark.note.database; public class NoteDbScheme { public static final class NoteTable{ public static final String name = "notes"; public static final class Cols{ public static final String UUID = "uuid"; public static final String TITLE = "title"; public static final String CONTENT = "content"; public static final String DATE = "date"; public static final String TAG = "tag"; } } }
類的名字叫NoteDbScheme,代表它是一個關於「計劃」的類,並且和database少不了干係,再來回憶Note這個類:程序員
public class Note { private UUID uuid; private String title; private String content; private Date date; private String tag; public Note(){ uuid = UUID.randomUUID(); date = new Date(); } public UUID getUuid() { return uuid; } public Date getDate() { return date; } public void setTitle(String title) { this.title = title; } public String getTitle() { return title; } public void setContent(String content) { this.content = content; } public String getContent() { return content; } public void setTag(String tag) { this.tag = tag; } public String getTag() { return tag; } }
很容易看出來Note類裏的私有字段和NoteDbScheme裏常量的值是一致的,言下之意,咱們能夠從數據庫裏取值賦給Note類中的字段,也能夠把Note類中字段的值存入數據庫。再回憶一下以前咱們是怎麼用Note類的,咱們在NoteLab建立了一個泛型爲Note的ArrayList,而後經過NoteListActivity把它渲染到layout,也就是用戶的界面上,這樣看來,Note類隱隱約約好像做爲一個溝通的橋樑(其實瞭解MVC模式的朋友應該很好理解)。sql
1.sql簡介:瞭解sql知識點這裏
瞭解sqlite知識點這裏數據庫
懶得看的就直接看這段sql語句,強行接受個人解釋就好了:數組
create table note( _int integer primary key autoincrement, uuid text, title text, content text, date text, tag text )
這段SQL語句的意思是,建立一個名叫「note」的表,包含6個字段,以第一個字段爲例,_int爲字段名,integer爲字段類型,primary key autoincrement表示它是主鍵並自增。請你們記住這個套路。app
2.SQLiteOpenHelper---數據庫好幫手
上面已經給出了建立表並定義字段的方法,在別的地方它能夠在終端或者腳本中運行,在Android世界裏天然要在類中大展宏圖。若是你的英語還能夠請你打開Android->sdk>doc,在官方文檔中搜索SQLiteOpenHelper,你會發現你要作的這個類基本上已經幫你封裝好了,你要作的就是繼承它,並依照你的需求去敲敲打打就行。好,來寫代碼:dom
public class NoteBaseHelper extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
這裏須要覆寫的onCreate方法就是咱們建立表的地方,當NoteBaseHelper被實例化時,它會自動檢測數據庫中有沒有note這個表,若是沒有就調用該方法。因此咱們把剛剛的sql語句寫進去:ide
@Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table " +NoteDbScheme.NoteTable.name+"(" + "_id integer primary key autoincrement," +NoteDbScheme.NoteTable.Cols.UUID+"," +NoteDbScheme.NoteTable.Cols.TITLE+"," +NoteDbScheme.NoteTable.Cols.CONTENT+"," +NoteDbScheme.NoteTable.Cols.DATE+"," +NoteDbScheme.NoteTable.Cols.TAG +")" ); }
這裏寫的和上面實際上是徹底同樣的,只不過咱們是用NoteDbScheme中的常量代替了字符串而已,這樣作的好處是若是之後表中的字段須要變動的話咱們只要在NoteDbScheme中變動就好了,而不須要動這裏的代碼。另外一個須要覆寫的onUpgrade在數據庫須要更新的時候調用。咱們再添加兩個常量來標記數據庫的名字和版本:學習
public class NoteBaseHelper extends SQLiteOpenHelper { public static final int VERSON = 1; public static final String DATABASE_NAME = "NoteBase"; @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table " +NoteDbScheme.NoteTable.name+"(" + "_id integer primary key autoincrement," +NoteDbScheme.NoteTable.Cols.UUID+"," +NoteDbScheme.NoteTable.Cols.TITLE+"," +NoteDbScheme.NoteTable.Cols.CONTENT+"," +NoteDbScheme.NoteTable.Cols.DATE+"," +NoteDbScheme.NoteTable.Cols.TAG +")" ); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
最後別忘了建立NoteBaseHelper的構造方法:
public NoteBaseHelper(Context context) { super(context,DATABASE_NAME,null,VERSON); }
DATABASE_NAME和VERSON就是咱們剛纔定義過的。
3.建立數據庫和表
前面咱們分析了,咱們用NoteLab類將數據渲染到前臺用戶界面,一樣的咱們也用它來與後臺數據庫交互,先來回顧一下NoteLab類:
public class NoteLab { private static NoteLab sNoteLab; //for the global use private ArrayList<Note> notes; private NoteLab(Context context){ notes = new ArrayList<Note>(); //generate 100 Note Objects // for (int i=0;i<100;i++){ // Note note = new Note(); // note.setTitle("this is title "+i); // note.setContent("this is content "+i+"balabalabalabalalabalabalabalabalala\nbalabalabalabalalabalabalabalabalala\nbalabalabalabalalabalabalabalabalala\nbalabalabalabalalabalabalabalabalala\nbalabalabalabalalabalabalabalabalala\n"); // notes.add(note); // } } public static NoteLab getNoteLab(Context context){ if (sNoteLab == null){ sNoteLab = new NoteLab(context); } return sNoteLab; } public ArrayList<Note> getNotes() { return notes; } public void addNote(Note note){ notes.add(note); } public Note getNote(UUID uuid){ for (Note note : notes){ if (note.getUuid().equals(uuid)){ return note; } } return null; } }
每一個方法的用途均可以經過命名來體現,實在看不懂的翻看我前面兩篇文章就好了。
public SQLiteDatabase getWritableDatabase ()
Added in API level 1
Create and/or open a database that will be used for reading and writing. The first time this is called, the database will be opened and onCreate(SQLiteDatabase), onUpgrade(SQLiteDatabase, int, int) and/or onOpen(SQLiteDatabase) will be called.
Once opened successfully, the database is cached, so you can call this method every time you need to write to the database. (Make sure to call close() when you no longer need the database.) Errors such as bad permissions or a full disk may cause this method to fail, but future attempts may succeed if the problem is fixed.
Database upgrade may take a long time, you should not call this method from the application main thread, including from ContentProvider.onCreate().
Returns
a read/write database object valid until close() is called
Throws
SQLiteException if the database cannot be opened for writing
這是Google官方文檔中關於SQLiteOpenHelper類的一個方法,用來建立或者打開一個數據庫,好,咱們就在NoteLab類的構造方法中來使用這個方法:
public class NoteLab { private static NoteLab sNoteLab; //for the global use private ArrayList<Note> notes; private Context context; private SQLiteDatabase database; private NoteLab(Context context){ notes = new ArrayList<Note>(); database = new NoteBaseHelper(context).getWritableDatabase(); //generate 100 Note Objects // for (int i=0;i<100;i++){ // Note note = new Note(); // note.setTitle("this is title "+i); // note.setContent("this is content "+i+"balabalabalabalalabalabalabalabalala\nbalabalabalabalalabalabalabalabalala\nbalabalabalabalalabalabalabalabalala\nbalabalabalabalalabalabalabalabalala\nbalabalabalabalalabalabalabalabalala\n"); // notes.add(note); // } } ...... }
這樣咱們在建立NoteLab的同時也就建立了NoteBase數據庫和note表。好,編譯,運行,這時候打開Android Device Monitor(Android Studio問號左邊的小機器人按鈕)
在Android中,全部App的本地數據庫都在data->data下,找到咱們這個應用的包名之下的databases目錄下,咱們看到了NoteBase數據庫,說明咱們成功建立了note表!
插入數據無非就是將一組鍵值對提交給操做數據的API,而這裏的鍵值對就是以ContentValues來組裝的(你們在這裏必定要去官方文檔搜到這個類好好讀一下,否則可能會在這裏卡住),咱們如今在NoteLab類中添加以下方法:
private ContentValues getValues(Note note){ ContentValues values = new ContentValues(); values.put(NoteDbScheme.NoteTable.Cols.UUID,note.getUuid().toString()![圖片描述][5]); values.put(NoteDbScheme.NoteTable.Cols.TITLE,note.getTitle()); values.put(NoteDbScheme.NoteTable.Cols.CONTENT,note.getContent()); values.put(NoteDbScheme.NoteTable.Cols.DATE,note.getDate().toString()); values.put(NoteDbScheme.NoteTable.Cols.TAG,note.getTag()); return values; }
代碼很容易讀,put方法接受的就是key--value對,這裏再一次用到了NoteDbScheme類,是否是以爲很奇妙很方便?如今咱們改寫以前的addNote方法:
public void addNote(Note note){ // notes.add(note); ContentValues values = getValues(note); database.insert(NoteDbScheme.NoteTable.name,null,values); }
這裏着重掌握insert方法,第一個參數接受將要插入的表名,第三個參數就是咱們須要組裝的ContentValues,第二個參數是關於插入空記錄的相關設置,你們能夠去查看文檔。好,編譯,運行:
點擊右上角加號,輸入數據幾組數據
很遺憾我如今並不會檢驗數據是否寫進表,無論了繼續寫代碼,去把數據庫的記錄讀出來!
寫了這麼多有點寫不下去了,不知道你是否是也看不下去了,你內心確定想這太冗雜了(誰讓我們使用java寫android呢,隨便寫寫就感受好多的樣子,可是換個角度想咱們能夠對外吹咱們的代碼量不少啊哈哈,雖然並無什麼卵用)。扯店犢子,你們回顧一下C語言中的指針和java語言中的引用(句柄?handle?指針?),或者是數組中的索引,咱們會發現這些重要的抽象對於咱們操做數據是頗有用的,對了,在Android咱們有Cursor(中文意思是遊標,對,就是遊標卡尺的那個遊標),咱們能夠變相的把它理解爲一個帶有指針的數組,咱們能夠經過操做「指針」來獲取其中的數組。每次咱們經過必定的條件進行數據庫查詢時,返回的就是一個Cursor, 它能夠依次指向查詢結果記錄的每一條。不當心又說多了,來,寫代碼,在NoteLab中建立以下方法:
private Cursor queryNote(String whereClause,String[] whereArgs){ Cursor cursor = database.query( NoteDbScheme.NoteTable.name, null, whereClause, whereArgs, null, null, null ); return cursor }
咱們須要關注的是query方法,第一個參數是要查詢的表名,第三個參數和第四個參數對應SQL語句中的where(少年,去回顧一下sql語句吧)。
但Cursor還不不太利於咱們的操做,來粉飾一波,在Cursor外面再裹上一層,所以就有了CursorWrapper,建立一個類讓它繼承CursorWrapper:
public class NoteCursorWrapper extends CursorWrapper { public NoteCursorWrapper(Cursor cursor){ super(cursor); } }
變動剛剛的queryNote方法:
private CursorWrapper queryNote(String whereClause, String[] whereArgs){
Cursor cursor = database.query( NoteDbScheme.NoteTable.name, null, whereClause, whereArgs, null, null, null ); return new CursorWrapper(cursor);
}
之因此說CursorWrapper方便,是由於咱們將查詢返回的Cursor傳入該類以後,能夠很方便的把查詢的值取出來,仍是看代碼:
......
......
別看了,太晚了,寫以前沒料到會有這麼長。明天繼續寫。