Day 21 - Active Android
สวัสดีครับ บทความนี้เป็นบทความที่ 21 แล้วนะครับ ที่ผมจะมาเขียน ในซีรีย์ 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
สำหรับวันนี้ขอนำเสนอเรื่อง ActiveAndroid เป็น Library ที่เอาไว้จัดการข้อมูล SQLite ในสไตล์ ORM ครับ ลักษณะคล้ายๆกับ Day 19 : GreenDAO ครับ โดยเมธอดที่ใช้งาน ค่อนข้างจำง่ายครับ เช่น save()
, delete()
Installation
ขั้นตอนการติดตั้ง ต้องดาวน์โหลดตัวโปรเจ็คมาก่อนครับ ทำการ clone จาก github
git clone https://github.com/pardom/ActiveAndroid.git
หรือจะดาวน์โหลดจากลิงค์นี้ ActiveAndroid-Master ทั้งสองวิธี เมื่อดาวน์โหลดมาแล้ว ก็ให้แตกซิปออก แล้วไปยังโฟลเดอร์ของโปรเจ็ค จากนั้นสั่งรันสคริป ant เพื่อให้มัน gen ไฟล์ ActiveAndroid.jar
มาให้ครับ
sudo apt-get install ant
ant
sudo apt-get install ant
คือการติดตั้ง ant ลงเครื่อง Ubuntu นะครับ สำหรับ Windows ผมไม่รู้วิธีการติดตั้งนะครับ ใครติดปัญหาตรงนี้ ก็หาวิธีกันเองนะครับ
หรือวิธีการ ข้างบนมันยากไป? ผมได้สร้างไฟล์ ActiveAndroid.jar ไว้ให้แล้ว ดาวน์โหลดไปใส่ที่โฟลเดอร์ libs
ของโปรเจ็คได้เลย
เมื่อเซฟไฟล์ jar ไว้ที่โฟลเดอร์ libs
ก็เปิดไฟล์ build.gradle
ขึ้นมา หาก compile fileTree
แล้วก็ไม่ต้องแก้ไร ให้กด Sync Gradle ใหม่แค่นั้น
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
แต่ถ้าหากใครไม่ได้สั่งให้ compile fileTree
ก็ระบุตำแหน่งของ libs ไปเลยครับ เช่นเซฟไว้ที่โฟลเดอร์ libs ก็เป็นแบบนี้
dependencies {
compile files('libs/ActiveAndroid.jar')
}
กด Sync Gradle เป็นอันเรียบร้อย
ผมเห็นใน Docs มีเขียนไว้ว่าสามารถโหลดจาก maven ได้ แต่ว่าไปเสริจหาดูแล้ว ไม่เจอใน maven แถมไม่รู้เวอร์ชันของ Library อีก เลยต้องโหลดไฟล์ jar แทน
Usage
มาถึงขั้นตอนการใช้งาน ActiveAndroid กันครับ
[1] ต้องทำการสร้างคลาส ที่ extends Application
ครับ ผมทำการตั้งชื่อให้มันว่า AAApplication.java
package com.devahoy.learn30androidlibraries.day21;
import android.app.Application;
import com.activeandroid.ActiveAndroid;
public class AAApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ActiveAndroid.initialize(this);
}
@Override
public void onTerminate() {
super.onTerminate();
ActiveAndroid.dispose();
}
}
ที่เมธอด onCreate()
มีการเรียกใช้ ActiveAndroid.initialize()
เพื่อสั่งให้มันทำงาน และเมธอด onTerminate()
ก็สั่งให้หยุดทำงาน ด้วย ActiveAndroid.dispose()
เมื่อปิดแอพครับ
[2] แก้ไข AndroidManifest.xml
โดยเพิ่ม meta-data และ application
<manifest ...>
<application
...
android:name=".AAApplication">
...
<meta-data android:name="AA_DB_NAME" android:value="Devahoy-AA.db" />
<meta-data android:name="AA_DB_VERSION" android:value="1" />
</application>
</manifest>
โดย AA_DB_NAME
และ AA_DB_VERSION
คือชื่อฐานข้อมูลและชื่อเวอร์ชันของฐานข้อมูลครับ หากใครเคยใช้ SQLiteOpenHelper ก็จะคุ้นๆกับ Constructor ที่มีการใช้ ชื่อฐานข้อมูล และชื่อเวอร์ชันครับ
Add Data
การเพิ่มข้อมูล ทำได้โดยการสร้างคลาสโมเดล ขึ้นมา แล้วทำการ extends com.activeandroid.Model
ครับ อยากเช่นผมต้องการสร้าง ข้อมูลหนังสือ ก็จะได้คลาส Book
แบบนี้
package com.devahoy.learn30androidlibraries.day21;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
@Table(name = "Book")
public class Book extends Model{
@Column(name = "title")
public String title;
@Column(name = "author")
public String author;
@Column(name = "publisher")
public String publisher;
@Column(name = "release_date")
public String releaseDate;
}
จะเห็นในโค๊ดมี Annotation ซึ่งตัว ActiveAndroid จะใช้ Annotation ไว้ระบุชื่อ Table และชื่อ Column ต่างๆ ในฐานข้อมูลครับ จากโค๊ด จะสังเกตเห็นว่า @Table(name = "Book")
คือประกาศให้โมเดลเนี้ย เวลาเซฟลงฐานข้อมูลจะชื่อ Book ส่วน @Column()
ก็ประกาศว่าแต่ละตัวแปร จะเซฟในฐานข้อมูลชื่อว่าอะไร เพื่อเวลา mapping จากฐานข้อมูลมาเป็นออปเจ็ค
อ้อถ้าอยากจะสร้าง Constructor ขึ้นมาเอง ก็ทำได้เช่นกัน แต่จำเป็นต้องสร้าง default constructor ขึ้นมาด้วย แบบนี้
package com.devahoy.learn30androidlibraries.day21;
import com.activeandroid.Model;
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
@Table(name = "Book")
public class Book extends Model{
public Book() {
super();
}
public Book(String title, String author, String publisher, String date) {
super();
this.title = title;
this.author = author;
this.publisher = publisher;
this.releaseDate = date;
}
}
ส่วนวิธีการเพิ่มข้อมูลลงฐานข้อมูล หลักจาที่มีโมเดล แล้วก็ทำได้ง่ายๆแบบนี้ครับ โดยการสร้าง new object จากนั้นก็ใช้เมธอด save()
เช่น
Book book = new Book("A Song of Ice and Fire",
"George R. R. Martin",
"Bantam Books",
"August 1996");
book.save();
Query Data
สำหรับวิธีการ Query ข้อมูล ก็ไม่ยากเลยครับ ชื่อคลาส และเมธอด จะคล้ายๆกับ Syntax ของ SQL เลยครับ เช่น Select
, From
, Where
เป็นต้นครับ เช่น ต้องการ query ข้อมูลหนังสือทั้งหมด ก็ทำได้ดังนี้
Select().from(Book.class).execute();
จะเห็นได้ว่า มันมีค่าเท่ากับ Select * From Book
คือเรียกคลาส Select()
หากไม่ระบุ parameter ลงไปแสดงว่าเลือกทั้งหมด ต่อมาก็ .from()
เป็นการระบุว่าจะเลือกจาก Table อะไร ในที่นี้คือคลาส Book
ส่วนตรง execute()
คือการ select แบบ List แต่ถ้าเลือกเป็น executeSingle()
ก็จะ select เพียงแค่ 1 column อย่างเช่น ตัวอย่างต่อไป เป็นการค้นหาหนังสือ โดยระบุไอดี
Select()
.from(Book.class)
.where("id = ?", String.valueOf(id))
.executeSingle();
}
หรืออีกวิธีคือ ใช้ load()
ครับ โดยระบุ id ลงไป เช่น
Book book = Book.load(Book.class, 1); // select * from Book where id = 1
Update & Delete
การ update และ delete สามารถทำได้แบบนี้
การ update จะคล้ายๆกับการ insert คือใช้เมธอด save()
อย่างเช่น เรา query ข้อมูลมาแล้ว แล้วต้องการอัพเดท ก็ทำได้แบบนี้
Book book = Book.load(Book.class, 1);
book.title = "Another name";
book.save();
การ delete ก็เช่นเดียวกัน เรียกออปเจ็คที่เราต้องการจะลบ จากนั้นก็ใช้เมธอด delete()
เช่น
Book book = Book.load(Book.class, 1);
book.delete()
หรือจะลบแบบนี้ก็ได้
Book.delete(Book.class, 1);
หรืออีกแบบ
new Delete().from(Book.class).where("Id = ?", 1).execute();
Create Project
ลองสร้างโปรเจ็คขึ้นมาซักหน่อยละกัน ตัวโปรเจ็คนี้ผมใ้ช้ไฟล์เดียวครับ คือ ActiveAndroidActivity.java
โดยทำการ extends ListActivity เพื่อจะโชว์ ListView และไม่ต้องใช้ไฟล์ layout ครับประหยุดเวลาดี สำหรับหลักการในแอพนี้ก็คือ
- ทำการ insert ข้อมูลเริ่มแรก ผ่านเมธอด
initSampleData()
- query ข้อมูลหนังสือทั้งหมด ด้วยเมธอด
findBooks()
- นำข้อมูลที่ได้ มาแสดงใน ListView
- กดไอเท็มแต่ละ ListView จะโชว์ชื่อของหนังสือเล่มนั้นๆ
โค๊ดที่ได้จะได้แบบด้านล่างนี้
package com.devahoy.learn30androidlibraries.day21;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.activeandroid.ActiveAndroid;
import com.activeandroid.query.Delete;
import java.util.ArrayList;
import java.util.List;
public class ActiveAndroidActivity extends ListActivity {
private List<Book> mBooks;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initSampleData();
mBooks = AAHelper.findBooks();
StringBuilder builder = new StringBuilder();
ArrayList<String> dataset = new ArrayList<String>();
for (Book book : mBooks) {
builder.setLength(0);
builder.append("Name : " + book.title + "\n");
builder.append("By : " + book.author + "\n");
builder.append("Publisher : " + book.publisher + "\n");
builder.append("Release Date : " + book.releaseDate + "\n");
dataset.add(builder.toString());
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, dataset);
setListAdapter(adapter);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Book book = AAHelper.findBookById(mBooks.get(position).getId());
Toast.makeText(this, "You choose " + book.title, Toast.LENGTH_SHORT).show();
}
private void initSampleData() {
new Delete().from(Book.class).execute();
ActiveAndroid.beginTransaction();
try {
Book book1 = new Book("Android Cookbook",
"Ian F. Darwin",
"O'Reilly Media" ,
"April 2012");
book1.save();
Book book2 = new Book("Android Recipes, 3rd Edition",
"Dave Smith , Jeff Friesen",
"Apress",
"February 2014");
book2.save();
Book book3 = new Book("Expert Android",
"Satya Komatineni, Dave MacLean",
"Apress",
"July 2013");
book3.save();
Book book4 = new Book("50 Android Hacks",
"Carlos Sessa",
"Manning Publications",
"May 2013");
book4.save();
Book book5 = new Book("Learn Java for Android Development, 3rd Edition",
"Jeff Friesen",
"Apress",
"March 2014");
book5.save();
Book book6 = new Book("Learning Android, 2nd Edition",
"Marko Gargenta, Masumi Nakamura",
"O'Reilly Media, Inc.",
"January 2014");
book6.save();
} finally {
ActiveAndroid.setTransactionSuccessful();
}
ActiveAndroid.endTransaction();
}
}
ส่วนคลาส AAHelper
ผมเอาไว้สำหรับสร้างเมธอด ไว้ query เฉยๆครับ มีโค๊ดนี้อยู่
package com.devahoy.learn30androidlibraries.day21;
import com.activeandroid.query.Select;
import java.util.List;
public class AAHelper {
public static List<Book> findBooks() {
return new Select()
.from(Book.class)
.execute();
}
public static Book findBookById(long id) {
return new Select()
.from(Book.class)
.where("id = ?", String.valueOf(id))
.executeSingle();
}
}
สุดท้าย ทดสอบรันโปรแกรม ได้ผลแบบนี้
สรุป
ลองเอาไปใช้กันดูนะครับ ส่วนตัวผมว่ามันใช้ง่ายกว่า GreenDAO อีกแฮะ แล้วการเรียกเมธอด หรือชื่อคลาส อะไรๆ ก็คล้ายๆ SQL Syntax เลย ทำให้มันแลดูเข้าใจง่าย สำหรับคนที่พอมีพื้นฐาน SQL มาบ้าง อ้ออีกอย่างมันรองรับ Transaction ด้วยเหมือนกัน แบบโค๊ดที่ผมเขียนด้านบน แต่ว่าลืมอธิบาย เอาเป็นว่า ลองๆดูโค๊ดประกอบละกันครับ ขอบคุณครับ
Happy Coding :D
Reference
- Authors
- Name
- Chai Phonbopit
- Website
- @Phonbopit