前言
我相信,在平時(shí)的開發(fā)過程中,大家一定會(huì)或多或少地接觸到SQLite。然而在使用它時(shí),我們往往需要做許多額外的工作,像編寫 SQL 語句與解析查詢結(jié)果等。所以,適用于 Android 的ORM?框架也就孕育而生了,現(xiàn)在市面上主流的框架有 OrmLite、SugarORM、Active Android、Realm 與 GreenDAO。而今天的主角便是?greenDAO,下面,我將詳解地介紹如何在?Android Studio?上使用?greenDAO,并結(jié)合代碼總結(jié)一些使用過程中的心得。
關(guān)于 greenDAO

簡單的講,greenDAO 是一個(gè)將對象映射到 SQLite 數(shù)據(jù)庫中的輕量且快速的 ORM 解決方案。(greenDAO is a light & fast ORM solution that maps objects to SQLite databases.)
而關(guān)于 ORM (Object Relation Mapping - 對象關(guān)系映射)的概念,可參見Wikipedia。
GREENDAO 設(shè)計(jì)的主要目標(biāo)
一個(gè)精簡的庫
性能最大化
內(nèi)存開銷最小化
易于使用的 APIs
對 Android 進(jìn)行高度優(yōu)化
GREENDAO 設(shè)計(jì)的主要特點(diǎn)
greenDAO 性能遠(yuǎn)遠(yuǎn)高于同類的ORMLite,具體測試結(jié)果可見官網(wǎng)
greenDAO 支持protocol buffer(protobuf)協(xié)議數(shù)據(jù)的直接存儲(chǔ),如果你通過 protobuf 協(xié)議與服務(wù)器交互,將不需要任何的映射。
與 ORMLite 等使用注解方式的 ORM 框架不同,greenDAO 使用「Code generation」的方式,這也是其性能能大幅提升的原因。
DAO CODE GENERATION PROJECT

這是其核心概念:為了在我們的 Android 工程中使用 greenDAO ,我們需要另建一個(gè)純 Java Project,用于自動(dòng)生成后繼 Android 工程中需要使用到的 Bean、DAO、DaoMaster、DaoSession 等類。
CORE CLASSES & MODELLING ENTITIES
關(guān)于以上幾個(gè)類的相關(guān)概念與作用,我將在下面的代碼(注釋)中詳細(xì)講解。
當(dāng)然,你也可以在官網(wǎng)中找到相關(guān)介紹。
讓我們開始吧
一. 在 ANDROID 工程中配置「GREENDAO GENERATOR」模塊
在 .src/main 目錄下新建一個(gè)與 java 同層級的「java-gen」目錄,用于存放由 greenDAO 生成的 Bean、DAO、DaoMaster、DaoSession 等類。


配置 Android 工程(app)的 build.gradle,如圖分別添加sourceSets與dependencies。

sourceSets?{
main?{
java.srcDirs?=?['src/main/java',?'src/main/java-gen']
}
}
compile?'de.greenrobot:greendao:1.3.7'
二. 新建「GREENDAO GENERATOR」模塊 (純 JAVA 工程)
通過 File -> New -> New Module -> Java Library -> 填寫相應(yīng)的包名與類名 -> Finish.



配置 daoexamplegenerator 工程的 build.gradle,添加 dependencies.

compile?'de.greenrobot:greendao-generator:1.3.1'
編寫?ExampleDaoGenerator?類,注意: 我們的 Java 工程只有一個(gè)類,它的內(nèi)容決定了「GreenDao Generator」的輸出,你可以在這個(gè)類中通過對象、關(guān)系等創(chuàng)建數(shù)據(jù)庫結(jié)構(gòu),下面我將以注釋的形式詳細(xì)講解代碼內(nèi)容。
public?class?ExampleDaoGenerator?{
public?static?void?main(String[]?args)?throws?Exception?{
//?正如你所見的,你創(chuàng)建了一個(gè)用于添加實(shí)體(Entity)的模式(Schema)對象。
//?兩個(gè)參數(shù)分別代表:數(shù)據(jù)庫版本號與自動(dòng)生成代碼的包路徑。
Schema?schema?=?new?Schema(1,?"me.itangqi.greendao");
//??????當(dāng)然,如果你愿意,你也可以分別指定生成的?Bean?與?DAO?類所在的目錄,只要如下所示:
//??????Schema?schema?=?new?Schema(1,?"me.itangqi.bean");
//??????schema.setDefaultJavaPackageDao("me.itangqi.dao");
//?模式(Schema)同時(shí)也擁有兩個(gè)默認(rèn)的?flags,分別用來標(biāo)示?entity?是否是?activie?以及是否使用?keep?sections。
//?schema2.enableActiveEntitiesByDefault();
//?schema2.enableKeepSectionsByDefault();
//?一旦你擁有了一個(gè)?Schema?對象后,你便可以使用它添加實(shí)體(Entities)了。
addNote(schema);
//?最后我們將使用?DAOGenerator?類的?generateAll()?方法自動(dòng)生成代碼,此處你需要根據(jù)自己的情況更改輸出目錄(既之前創(chuàng)建的?java-gen)。
//?其實(shí),輸出目錄的路徑可以在?build.gradle?中設(shè)置,有興趣的朋友可以自行搜索,這里就不再詳解。
new?DaoGenerator().generateAll(schema,?"/Users/tangqi/android-dev/AndroidStudioProjects/MyGreenDAO/app/src/main/java-gen");
}
/**
*?@param?schema
*/
private?static?void?addNote(Schema?schema)?{
//?一個(gè)實(shí)體(類)就關(guān)聯(lián)到數(shù)據(jù)庫中的一張表,此處表名為「Note」(既類名)
Entity?note?=?schema.addEntity("Note");
//?你也可以重新給表命名
//?note.setTableName("NODE");
//?greenDAO?會(huì)自動(dòng)根據(jù)實(shí)體類的屬性值來創(chuàng)建表字段,并賦予默認(rèn)值
//?接下來你便可以設(shè)置表中的字段:
note.addIdProperty();
note.addStringProperty("text").notNull();
//?與在?Java?中使用駝峰命名法不同,默認(rèn)數(shù)據(jù)庫中的命名是使用大寫和下劃線來分割單詞的。
//?For?example,?a?property?called?“creationDate”?will?become?a?database?column?“CREATION_DATE”.
note.addStringProperty("comment");
note.addDateProperty("date");
}
}
三. 生成 DAO 文件(數(shù)據(jù)庫)
執(zhí)行 generator 工程,如一切正常,你將會(huì)在控制臺看到如下日志,并且在主工程「java-gen」下會(huì)發(fā)現(xiàn)生成了DaoMaster、DaoSession、NoteDao、Note共4個(gè)類文件。

如果在此處出錯(cuò),你可以依據(jù)錯(cuò)誤日志進(jìn)行排查,主要看是否輸出目錄存在?其他配置是否正確?等
四. 在 ANDROID 工程中進(jìn)行數(shù)據(jù)庫操作
這里,我們只創(chuàng)建一個(gè) NodeActivity 類,用于測試與講解 greenDAO 的增、刪、查功能。
activity_note.xml
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:id="@+id/editTextNote"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Enter?new?note"
android:inputType="text">
android:id="@+id/buttonAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onMyButtonClick"
android:text="Add">
android:id="@+id/buttonSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onMyButtonClick"
android:text="Search">
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
NoteActivity.java
public?class?NoteActivity?extends?ListActivity?{
private?SQLiteDatabase?db;
private?EditText?editText;
private?DaoMaster?daoMaster;
private?DaoSession?daoSession;
private?Cursor?cursor;
public?static?final?String?TAG?=?"DaoExample";
@Override
public?void?onCreate(Bundle?savedInstanceState)?{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_note);
//?官方推薦將獲取?DaoMaster?對象的方法放到?Application?層,這樣將避免多次創(chuàng)建生成?Session?對象
setupDatabase();
//?獲取?NoteDao?對象
getNoteDao();
String?textColumn?=?NoteDao.Properties.Text.columnName;
String?orderBy?=?textColumn?+?"?COLLATE?LOCALIZED?ASC";
cursor?=?db.query(getNoteDao().getTablename(),?getNoteDao().getAllColumns(),?null,?null,?null,?null,?orderBy);
String[]?from?=?{textColumn,?NoteDao.Properties.Comment.columnName};
int[]?to?=?{android.R.id.text1,?android.R.id.text2};
SimpleCursorAdapter?adapter?=?new?SimpleCursorAdapter(this,?android.R.layout.simple_list_item_2,?cursor,?from,
to);
setListAdapter(adapter);
editText?=?(EditText)?findViewById(R.id.editTextNote);
}
private?void?setupDatabase()?{
//?通過?DaoMaster?的內(nèi)部類?DevOpenHelper,你可以得到一個(gè)便利的?SQLiteOpenHelper?對象。
//?可能你已經(jīng)注意到了,你并不需要去編寫「CREATE?TABLE」這樣的?SQL?語句,因?yàn)?greenDAO?已經(jīng)幫你做了。
//?注意:默認(rèn)的?DaoMaster.DevOpenHelper?會(huì)在數(shù)據(jù)庫升級時(shí),刪除所有的表,意味著這將導(dǎo)致數(shù)據(jù)的丟失。
//?所以,在正式的項(xiàng)目中,你還應(yīng)該做一層封裝,來實(shí)現(xiàn)數(shù)據(jù)庫的安全升級。
DaoMaster.DevOpenHelper?helper?=?new?DaoMaster.DevOpenHelper(this,?"notes-db",?null);
db?=?helper.getWritableDatabase();
//?注意:該數(shù)據(jù)庫連接屬于?DaoMaster,所以多個(gè)?Session?指的是相同的數(shù)據(jù)庫連接。
daoMaster?=?new?DaoMaster(db);
daoSession?=?daoMaster.newSession();
}
private?NoteDao?getNoteDao()?{
return?daoSession.getNoteDao();
}
/**
*?Button?點(diǎn)擊的監(jiān)聽事件
*
*?@param?view
*/
public?void?onMyButtonClick(View?view)?{
switch?(view.getId())?{
case?R.id.buttonAdd:
addNote();
break;
case?R.id.buttonSearch:
search();
break;
default:
Log.d(TAG,?"what?has?gone?wrong??");
break;
}
}
private?void?addNote()?{
String?noteText?=?editText.getText().toString();
editText.setText("");
final?DateFormat?df?=?DateFormat.getDateTimeInstance(DateFormat.MEDIUM,?DateFormat.MEDIUM);
String?comment?=?"Added?on?"?+?df.format(new?Date());
//?插入操作,簡單到只要你創(chuàng)建一個(gè)?Java?對象
Note?note?=?new?Note(null,?noteText,?comment,?new?Date());
getNoteDao().insert(note);
Log.d(TAG,?"Inserted?new?note,?ID:?"?+?note.getId());
cursor.requery();
}
private?void?search()?{
//?Query?類代表了一個(gè)可以被重復(fù)執(zhí)行的查詢
Query?query?=?getNoteDao().queryBuilder()
.where(NoteDao.Properties.Text.eq("Test1"))
.orderAsc(NoteDao.Properties.Date)
.build();
//??????查詢結(jié)果以?List?返回
//??????List?notes?=?query.list();
//?在?QueryBuilder?類中內(nèi)置兩個(gè)?Flag?用于方便輸出執(zhí)行的?SQL?語句與傳遞參數(shù)的值
QueryBuilder.LOG_SQL?=?true;
QueryBuilder.LOG_VALUES?=?true;
}
/**
*?ListView?的監(jiān)聽事件,用于刪除一個(gè)?Item
*?@param?l
*?@param?v
*?@param?position
*?@param?id
*/
@Override
protected?void?onListItemClick(ListView?l,?View?v,?int?position,?long?id)?{
//?刪除操作,你可以通過「id」也可以一次性刪除所有
getNoteDao().deleteByKey(id);
//????????getNoteDao().deleteAll();
Log.d(TAG,?"Deleted?note,?ID:?"?+?id);
cursor.requery();
}
}
五. 運(yùn)行結(jié)果
一切就緒,讓我們看看效果吧!運(yùn)行程序,分別執(zhí)行添加按鈕、刪除(點(diǎn)擊 List 的 Item)與查詢按鈕,可以在控制臺得到如下日志:



最后
本文的 Demo 下載鏈接:https://github.com/tangqi92/MyGreenDAO
本教程旨在介紹 greenDAO 的基本用法與配置,更高級與詳細(xì)的使用,請參見官網(wǎng)
如本文有任何錯(cuò)誤與遺漏,歡迎指正。同時(shí)我期待與大家成為朋友,所以歡迎在社交網(wǎng)絡(luò)上互粉!??!
References & More
http://greendao-orm.com/https://github.com/greenrobot/greenDAOhttp://stackoverflow.com/questions/tagged/greendaohttps://groups.google.com/forum/#!forum/greendao