Android ORM 框架之 greenDAO 使用心得

前言

我相信,在平時(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,如圖分別添加sourceSetsdependencies。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,192評論 25 708
  • greenDAO官方主頁:http://greendao-orm.com/ 官方主頁新地址:http://gree...
    sunny_zhang閱讀 10,320評論 12 49
  • 今年讀了什么書? 說實(shí)話,今年買了不少書。今年辦了省圖的借書卡。今年裝了三個(gè)以上的手機(jī)讀書APP。每天晚上都有很多...
    八月日記本閱讀 404評論 1 1
  • 愛? 唉…… 愛? 愛! 愛? 跑! 愛? 幻。 愛? 妄。 愛? ?? 息怒貪嗔癡,柴米油鹽醋 江山美人志,星辰大海路
    萬事皆三閱讀 259評論 2 1
  • 【11月22日 326/3650 踐行結(jié)果檢視】 1,【晨間日記、每日要事、今日檢視】——心得:全勤 2,【月有效...
    佩娜閱讀 792評論 0 5

友情鏈接更多精彩內(nèi)容