Day 19 - GreenDAO
![Day 19 - GreenDAO](/_vercel/image?url=%2Fimages%2F2014%2F07%2F30-days.png&w=828&q=80)
สวัสดีครับ บทความนี้เป็นบทความที่ 19 แล้วนะครับ ที่ผมจะมาเขียน ในซีรีย์ Learn 30 Android Libraries in 30 days
สำหรับบทความทั้งหมด อ่านได้จากด้านล่างครับ
- Day 1 : AndroidStaggered Grid
- Day 2 : Paralloid
- Day 3 : Retrofit
- Day 4 : SwipeRefreshLayout
- Day 5 : Android GraphView
- Day 6 : Holo Color Picker
- Day 7 : Android Async Http
- Day 8 : Crashlytics
- Day 9 : Butter Knife
- Day 10 : Android Annotations
- Day 11 : DateTimePicker
- Day 12 : Circular Progress Button
- Day 13 : ViewPager
- Day 14 : ViewPagerIndicator
- Day 15 : FadingActionBar
- Day 16 : AutofitTextView
- Day 17 : SwipeListView
- Day 18 : ShowcaseView
- Day 19 : GreenDAO
- Day 20 : AndroidViewAnimation
- Day 21 : ActiveAndroid
- Day 22 : Twitter4J
- Day 23 : ListViewAnimations
- Day 24 : AndEngine
- Day 25 : EazeGraph
- Day 26 : Cardslib
- Day 27 : AdapterKit
- Day 28 : WeatherLib
- Day 29 : FlatUI
- Day 30 : Android Firebase
สำหรับวันนี้ขอนำเสนอเรื่อง greenDAO เป็น ORM Tool ตัวหนึงบน Android ครับ (ORM คือ Object Relational Mapping) มันคือการ Mapping ตัว Java class ของเรา กับ SQLite ผ่าน Interface
GreenDAO คืออะไร?
greenDAO เป็น Open Source Project ที่ช่วยการทำงานร่วมกับ SQLite :CRUD (CREATE, READ, UPDATE, DELETE) ทำได้ง่ายมากครับ โดยผ่าน ORM (Object Relational Model) คือใช้คลาส Java ของเรา mapping กับ SQLite โดยมี Dao Interface เป็นตัวเชื่อมต่ออีกที แล้วไอ้เจ้า ORM มันคืออะไร? หลายคนคงจะสงสัย ไปหาอ่านเพิ่มเติมกันเองนะครับ
Step 1 : Installation
การติดตั้ง greenDAO จะมีด้วยกัน 2 ตัวนะครับ นั่นก็คือ
GreenDAO
: เป็น Library ของ GreenDAO ธรรมดาDaoGenerator
: จะเป็นตัวเอาไว้ Generate ให้กลายเป็น ORM ให้เรานะครับ
Step 2 : Create Generator Module
ฉะนั้นขั้นตอนแรก เราจะต้องมาทำตัว Generate กันก่อนครับ เริ่มด้วยการสร้าง Module ขึ้นมาใหม่ 1 โมดูล คลิ๊กขวาที่โปรเจ็ค => ์New => Module
ผมทำการตั้งชื่อโมดูลว่า DaoGenerator
จะเห็นว่า มี folder มาอยู่ใน Project ของเราแล้วครับ
ลองตรวจสอบไฟล์ settings.gradle
ว่าได้ include โมดูลที่เราสร้างไปหรือยัง ต้องเป็นแบบนี้ (app คือชื่อโมดูลหลักของผมนะครับ ตัวโปรเจ็คนั่นแหละ)
1include ':app', ':DaoGenerator'
ต่อมาเปิด ไฟล์ build.gradle
ในโมดูล DaoGenerator
ขึ้นมา แก้ไขไฟล์เป็นแบบนี้
1project(':DaoGenerator') {2 apply plugin: 'application'3 apply plugin: 'java'4
5 mainClassName = "com.devahoy.learn30androidlibraries.daogenerator.MyDaoGenerator"6 outputDir = "../app/src/main/java-gen"7
8 dependencies {9 compile fileTree(dir: 'libs', include: ['*.jar'])10 compile('de.greenrobot:DaoGenerator:1.3.0')11 }12
13 task createDocs {14 def docs = file(outputDir)15 docs.mkdirs()16 }17
18 run {19 args outputDir20 }21}
อธิบายโค๊ดด้านบน
mainClassName
: เป็นคลาสที่เราจะทำการ generate (ใครใช้ package name ต่างจากนี้ ก็ต้องเปลี่ยนเป็นของตัวเองด้วย)
outputDir
: เป็น path ของ folder ที่เราจะให้ generate ไป ตัวอย่างคือจะ gen ไปที่โมดูล app/src/main/java-gen
ครับ (หากใครมีโครงสร้างโปรเจ็คหรือโมดูลที่ชื่อต่างกัน ก็ต้องเปลี่ยนตรงนี้ด้วย)
run()
: เป็น gradle script เอาไว้สั่งรัน โดยมี argument เป็น outputDir
Step 3 : Create Generator Class
ต่อมาทำการสร้างคลาสสำหรับ Generate ชื่อว่า MyDaoGenerator.java
ขึ้นมา
1package com.devahoy.learn30androidlibraries.daogenerator;2
3import java.io.File;4
5import de.greenrobot.daogenerator.DaoGenerator;6import de.greenrobot.daogenerator.Entity;7import de.greenrobot.daogenerator.Schema;8
9public class MyDaoGenerator {10
11 public static void main(String[] args) throws Exception {12 Schema schema = new Schema(1, "com.devahoy.learn30androidlibraries");13 Entity player = schema.addEntity("Player");14
15 player.addIdProperty();16 player.addStringProperty("name");17 player.addStringProperty("club");18
19 new DaoGenerator().generateAll(schema, args[0]);20 }21}
โค๊ดด้านบน ผมทำการสร้าง Schema ขึ้นมา เป็นเหมือนการสร้าง Database ขึ้นมา้ก้อนนึง ชื่อว่า com.devahoy.learn30androidlibraries
และเป็นเวอร์ชัน 1 ต่อมาผมสร้าง Entity ที่ชื่อว่า Player
ส่วนนี้โค๊ดจะถูก generate ไปเป็นคลาส
Player
และ PlayerDAO
โดยภายในคลาสโมเดล Player มี 3 field คือ Id, Name และ Club ครับ สุดท้าย สั่ง DaoGenerator().generateAll()
โดยระบุเป็น args[0]
คือ outputDir ที่เซตไว้ใน build.gradle
ต่อมา กดที่แท็ป Gradle อยู่ขวามือๆ แล้วมองหา :DaoGenerator
แล้วดับเบิลคลิกที่ script run
จะได้ดังภาพ
ไฟล์จะถูก generate ไปที่โฟลเดอร์ที่ระบุไว้
ที่นี้ก็ลองไปดูที่โฟลเดอร์ app/main/src/java-gen
จะเห็นคลาสที่ถูก generate มาเต็มเลย ในส่วนนี้แหละครับ ที่เราจะเอาไปใช้ในโปรเจ็คของเรา สำหรับส่วน Generate ก็หมดหน้าที่เพียงเท่านี้ :D
Step 4 : Setup greenDAO Project
หลักจากที่เรา generate เรียบร้อยแล้ว ต่อมาก็ต้องมา setup ตัวโปรเจ็คของเราบ้าง ให้ทำการเปิดไฟล์ build.gradle
แล้วเพิ่ม dependencies ของ greenDao ลงไป (คนละตัวกับตัว generate นะครับ)
ต่อมาทำการ setup SourceSets ด้วยครับ เนื่องจาก default มันรู้จักแค่ src/main/java
ไม่ได้รู้จักโฟลเดอร์ src/main/java-gen
ที่เราทำการสร้างมาใหม่ ต้องไปบอกให้มันรู้ครับ โดยเพิ่มโค๊ดไปใน block android ดังนี้
1android {2 sourceSets {3 main {4 java {5 srcDir 'src/main/java'6 // for greenDAO7 srcDir 'src/main/java-gen'8 }9 }10 }11}12dependencies {13 compile 'de.greenrobot:greendao:1.3.7'14}
ทำการ Sync Gradle เป็นอันเรียบร้อย
SourceSets คืออะไร? อ่านที่นี่
Step 5 : Create Database
ต่อมาทำการสร้าง GreenDaoApplication.java
ขึ้นมาก่อนครับ เพื่อเอาไว้สร้าง Database โดยทำการ extends Application ดังนี้
1package com.devahoy.learn30androidlibraries.day19;2
3import android.app.Application;4import android.database.sqlite.SQLiteDatabase;5
6import com.devahoy.learn30androidlibraries.DaoMaster;7import com.devahoy.learn30androidlibraries.DaoSession;8
9public class GreenDaoApplication extends Application {10
11 DaoSession mDaoSession;12
13 @Override14 public void onCreate() {15 super.onCreate();16 setupDatabase();17 }18
19 private void setupDatabase() {20 DaoMaster.DevOpenHelper helper =21 new DaoMaster.DevOpenHelper(this, "MyGreenDao.db", null);22 SQLiteDatabase db = helper.getWritableDatabase();23 DaoMaster daoMaster = new DaoMaster(db);24 mDaoSession = daoMaster.newSession();25 }26
27 public DaoSession getDaoSession() {28 return mDaoSession;29 }30}
อธิบายโค๊ดด้านบน new DaoMaster.DevOpenHelper()
เปรียบเสมือนการใช้งาน SQLiteOpenHelper ครับ เราไม่ต้องมานั่งทำการ implement แล้ว สั่ง CREATE TABLE เลยครับ ตัว greenDAO มันทำให้เราเรียบร้อยแล้ว โดยใช้ DaoMaster
สุดท้ายมีเมธอด getDaoSession()
เพื่อทำการส่ง DaoSession
อันนี้จะเอาไปใช้ใน Activity ครับ ก่อนที่เราจะทำการ insert, update, delete เราต้องมี Session ก่อน
Session คืออะไร? อ่านเพิ่มเติม
เมื่อเราทำการสร้าง Custom Application เราจำเป็นต้องไปตั้งค่าที่ไฟล์ AndroidManifest.xml
ด้วยครับ ตรงส่วน android:name=".GreenDaoApplication">
ดังนี้
1<manifest xmlns:android="http://schemas.android.com/apk/res/android"2 package="com.devahoy.learn30androidlibraries" >3 <application4 ...5 android:name=".day19.GreenDaoApplication">6 <activity>7 ...8 </activity>9 </application>10
11</manifest>
Step 6 : Create Activity
สุดท้ายละครับ ทำการสร้าง Activity ขึ้นมา โดยตัวอย่าง ผมจะให้มันแสดงข้อมูลจาก ฐานข้อมูลแบบ List ง่ายๆครับ
1package com.devahoy.learn30androidlibraries.day19;2
3import android.app.ListActivity;4import android.os.Bundle;5import android.widget.ArrayAdapter;6
7import com.devahoy.learn30androidlibraries.DaoSession;8import com.devahoy.learn30androidlibraries.Player;9import com.devahoy.learn30androidlibraries.PlayerDao;10
11import java.util.ArrayList;12import java.util.List;13
14public class GreenDAOActivity extends ListActivity {15
16 ArrayList<String> mDataset = new ArrayList<String>();17
18 @Override19 protected void onCreate(Bundle savedInstanceState) {20 super.onCreate(savedInstanceState);21
22 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,23 android.R.layout.simple_list_item_1, mDataset);24 setListAdapter(adapter);25 }26}
ด้านบนผมจะแค่โชว์ ข้อมูลเป็นลิสท์เฉยๆ ทำให้ใช้แค่ ListActivity ก็พอครับ ส่วนข้อมูล mDataset
นี่แหละครับ ที่จะเอามาจากฐานข้อมูล มาดูวิธีการกันดีกว่า ว่าจะเรียกข้อมูลได้ยังไง?
Insert
การ Insert ข้อมูลทำได้ผ่านตัว PlayerDAO
ครับ (อันนี้ถ้าตรง generate เราเซตค่า Entity เป็นชื่ออื่น มันก็จะเป็นชื่อนั้นๆ + DAO นะครับ)
1Player player = new Player(1L, "my name", "my club");2PlayerDAO.insert(player);
READ / QUERY
การ Query ข้อมูล ก็ทำผ่าน PlayerDAO
เช่นกันครับ แบบนี้
1PlayerDAO.loadAll();2PlayerDao.load(key); // query แบบระบุ id
UPDATE
การ update ก็ทำเหมือนกับการ insert เลย คือใช้ Player เป็น parameter ครับ
1oldPlayer;2PlayerDAO.update(oldPlayer);
DELETE
การ delete มีให้เลือกแบบ deleteAll() คือลบทั้งหมด ลบแบบระบุออปเจ็ค และลบแบบระบุ id
1PlayerDAO.delete(player);2PlayerDAO.deleteByKey(id);3PlayerDAO.deleteAll();
สำหรับวิธีการ CRUD กับ SQLite ก็มีประมาณนี้ครับ สุดท้ายผมนำ Insert มาใช้อย่างเดียว ได้แบบนี้
1package com.devahoy.learn30androidlibraries.day19;2
3import android.app.ListActivity;4import android.os.Bundle;5import android.widget.ArrayAdapter;6
7import com.devahoy.learn30androidlibraries.DaoSession;8import com.devahoy.learn30androidlibraries.Player;9import com.devahoy.learn30androidlibraries.PlayerDao;10
11import java.util.ArrayList;12import java.util.List;13
14public class GreenDAOActivity extends ListActivity {15
16 GreenDaoApplication mApplication;17 DaoSession mDaoSession;18 PlayerDao mPlayerDao;19 ArrayList<String> mDataset = new ArrayList<String>();20
21 @Override22 protected void onCreate(Bundle savedInstanceState) {23 super.onCreate(savedInstanceState);24
25 mApplication = (GreenDaoApplication) getApplication();26 mDaoSession = mApplication.getDaoSession();27
28 initSampleData();29
30 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,31 android.R.layout.simple_list_item_1, mDataset);32 setListAdapter(adapter);33 }34
35 void initSampleData() {36 mPlayerDao = mDaoSession.getPlayerDao();37
38 mPlayerDao.deleteAll();39
40 Player messi = new Player(1L, "Leonel Messi", "FC Barcelona");41 Player ronaldo = new Player(2L, "Cristiano Ronaldo", "Real Madrid");42 Player gerrard = new Player(3L, "Steven Gerrard", "Liverpool");43 Player persie = new Player(4L, "Robin Van Persie", "Man Utd");44 Player teerasil = new Player(5L, "Teerasil Dangda", "UD Almeria");45
46 mPlayerDao.insert(messi);47 mPlayerDao.insert(ronaldo);48 mPlayerDao.insert(gerrard);49 mPlayerDao.insert(persie);50 mPlayerDao.insert(teerasil);51
52 mDataset = new ArrayList<String>();53
54 List<Player> players = mPlayerDao.loadAll();55 for (Player player : players) {56 mDataset.add("Name : " + player.getName() + "\nClub : " + player.getClub());57 }58 }59}
จากโค๊ดด้านบน getApplication()
เป็นการเรียก Application ที่แอพนี้ใช้อยู่ครับ นั่นก็คือ GreenDaoApplication
และก็ getDaoSession()
เพื่อทำการเรียก DaoSession
มาก่อนครับ ถึงจะทำการ getPlayerDao()
ได้ จะเห็นว่าผมใช้ PlayerDAO.insert()
เพื่อทำการเพิ่มข้อมูลลงฐานข้อมูล ใช้ PlayerDao.loadAll()
เพื่อทำการ query ข้อมูลทั้งหมดในฐานข้อมูลมาโชว์ใน ListView และใช้ PlayerDAO.deleteAll()
ทำการลบข้อมูลทั้งหมด ทุกครั้งที่เปิดแอพครับ ส่วน update ไม่ได้ทำครับ :D
สรุป
ส่วนตัว ผมก็เพิ่งมาเคยใช้ ORM ใน Android ก็วันนี้แหละครับ ปกติใช้แต่ SQLiteOpenHelper ส่วน ORM ผมเคยใช้แต่บน Java Spring หลักจากใช้ greenDAO ลองเล่นกับมันดูราวๆ 3-4 ชม. (หมดไปกับการติดตั้ง) แล้วรู้สึกว่าติดใจครับ ใช้งานง่าย ไม่ต้องไปทำการสร้าง SQL Syntax ไม่ต้องไป get Cursor เอง เรียกผ่าน Interface ที่ greenDAO เตรียมไว้ให้ได้เลย สำหรับใครที่ผ่านมาอ่าน ก็ลองนำไปใช้ดูนะครับ สุดท้ายโปรเจ็คอัพเดทล่าสุดครับ 30-android-libraries-in-30-days
Reference
- Authors
-
Chai Phonbopit
เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust