0% found this document useful (0 votes)
25 views

Android Sqlite Basics

- SQLite is the default database used in Android applications to store structured data in a local database on the device. It allows storing multiple records of the same type, like employee records with fields like ID, name, etc. - The Android SDK includes SQLite and APIs to easily create, query, update and delete data from a SQLite database within an app. A SQLite database file is stored privately for each app. - The SQLiteOpenHelper class provides methods to simplify common database tasks like creating/upgrading the database schema and internal tables on app install/update. Developers override methods like onCreate() and onUpgrade() to handle these tasks.

Uploaded by

CRM HUG
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views

Android Sqlite Basics

- SQLite is the default database used in Android applications to store structured data in a local database on the device. It allows storing multiple records of the same type, like employee records with fields like ID, name, etc. - The Android SDK includes SQLite and APIs to easily create, query, update and delete data from a SQLite database within an app. A SQLite database file is stored privately for each app. - The SQLiteOpenHelper class provides methods to simplify common database tasks like creating/upgrading the database schema and internal tables on app install/update. Developers override methods like onCreate() and onUpgrade() to handle these tasks.

Uploaded by

CRM HUG
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 45

Android SQLite Basics

Android: www.3bugs.com
Android ก SQLite
ฐานขอมูล (database) คือวิธีหนึ่งในการจัดเก็บขอมูลในระบบแอนดรอยด เหมาะสําหรับ
ขอมูลที่มีโครงสรางแบบเดียวกันหลายๆชุด ยกตัวอย)างเช)นขอมูลพนักงาน ซึ่งขอมูลแต)ละชุด (พนักงาน
แต)ละคน) ประกอบดวยรหัสพนักงาน ชื่อ นามสกุล และวันเกิด เป/นตน
รหัสพนักงาน ชื อ นามสกุล วันเกิด
6473 สมชาย ไม้อ่อน 07/11/1985
6783 สมศักดิ รักงาน 12/07/1979
6777 ยุวดี ศรีสะอาด 03/01/1976
6789 รุง่ อรุณ กุลบุตร 01/09/1984

แอนดรอยดมาพรอมกับระบบฐานขอมูล SQLite และจัดเตรียม API (Application Program-


ming Interface) ไวใหเราใชทํางานกับฐานขอมูล SQLite ไดทันที โดยไม)ตองติดตั้งอะไรเพิ่มเติม ซึ่ง
ตัวฐานขอมูลจะถูกเก็บอยู)บนเครื่องแอนดรอยดของผูใช หรือเรียกว)าเป/น local database

ฐานข้อมูลทีแ+ อพของเราสร้างขึน0 จะถูกเก็บไว้ใน internal directory (ไดเร็คทอรีสว่ นตัวของแอพ


บน internal storage) ซึง+ แอพอื+นๆไม่สามารถเข้าถึงได้

การใชงานฐานขอมูล SQLite ไม)ตองมีการเซ็ตอัพและเตรียมฐานขอมูลไวล)วงหนาตั้งแต)ตอน


พัฒนาแอพ แต)เราจะเขียนโคดใหสรางฐานขอมูลขึ้นตอนที่แอพทํางานเลย (สรางในช)วง runtime) ซึ่ง
แอนดรอยดมี "คลาสตัวช)วย" (helper class) ไวอํานวยความสะดวกในการสรางฐานขอมูล อัพเกรด
ฐานขอมูล และอ)าน/เขียนขอมูลในฐานขอมูล

%& (' ) )ก% ก &*% +


SQLite คือฐานขอมูลเชิงสัมพันธ (relational database) เช)นเดียวกับฐานขอมูลยอดนิยม
อื่นๆ ลักษณะสําคัญของฐานขอมูลประเภทนี้คือ ในฐานขอมูลจะประกอบดวยตารางขอมูลหรือ เทเบิล
(table) ตั้งแต) 1 เทเบิลขึ้นไป และแต)ละเทเบิลจะประกอบดวยแถว (row) กับคอลัมน (column)
ดังรูป

Android: www.3bugs.com
( # ) (column) 3 4 56# ) (field) 4? ( # )
3 4 ?4 56# )
EmpID Firstname Lastname Birthdate
6473 07/11/1985
6783 ก ก 12/07/1979 ;< (row) 3 4
& ( ) (record)
6777 ! 03/01/1976
6789 " ก#$% 01/09/1984

@ A#

&'&$#

เมื่อจะใชงานฐานขอมูลในการเก็บขอมูล อันดับแรกตองออกแบบโครงสร$างของฐานขอมูลก)อน
ว)าจะใหมีเทเบิลอะไรบาง (ในฐานขอมูลหนึ่งสามารถมีไดมากกว)า 1 เทเบิล) แต)ละเทเบิลมีคอลัมนอะไร
และเก็บขอมูลชนิดใด ซึ่งโครงสรางของฐานขอมูลนี้เรียกว)า schema
เมื่อพัฒนาแอพไปเรื่อยๆ เราอาจมีความจําเป/นตองปรับเปลี่ยน schema ของฐานขอมูล เช)น
เพิ่มเทเบิลหรือคอลัมนเพื่อรองรับฟWเจอรใหม)ของแอพ หรือเราอาจจัดระเบียบขอมูลใหม)โดยลบเทเบิล
หนึ่ง และยายขอมูลจากเทเบิลนั้นไปเก็บไวในอีกเทเบิลหนึ่งแทน เป/นตน
จากที่กล)าวมาจะเห็นว)า บางครั้งการพัฒนาแอพเวอรชั่นใหม) ไม)เพียงแต)โคดจาวาในแอพจะ
เปลี่ยนไปเท)านั้น แต) "ความคาดหวัง" ของโคดจาวาที่มีต)อ schema ของฐานขอมูลยังเปลี่ยนไปดวย
โดยเวอรชั่น 1 ของแอพอาจทํางานกับ schema ที่เราออกแบบไวเริ่มแรก แต)พอถึงเวลาที่เราปรับปรุง
แอพเป/นเวอรชั่น 5 เราอาจตองการ schema ที่เปลี่ยนไปก็ได
แอนดรอยดมีวิธีใหเราอัพเกรดฐานขอมูลไดอย)างสะดวก โดยผ)านทาง helper class ซึ่งก็คือ
คลาส SQLiteOpenHelper

Android: www.3bugs.com
+ กก , % SQLiteOpenHelper
การใชงาน SQLite จะเริ่มจากการสรางคลาสใหม)ที่เป/นซับคลาสของ (สืบทอดจาก) คลาส
SQLiteOpenHelper ในแพคเกจ android.database.sqlite และทําการ override เมธอดเพื่อตอบ

คําถามแอนดรอยด 2 ขอต)อไปนี้
จะเกิดอะไรขึ้นเมื่อแอพของเราถูกติดตั้งและรันขึ้นมาครั้งแรกสุด ซึ่งตอนนั้นแอพของเรายัง
ไม)มีฐานขอมูล? เราตองจัดการสรางเทเบิลต)างๆขึ้นมาตาม schema ที่ออกแบบไว รวมถึง
อาจมีการเพิ่มขอมูลลงในฐานขอมูลเพื่อเตรียมขอมูลตั้งตนดวย
จะเกิดอะไรขึ้นเมื่อแอพเวอรชั่นใหม)ของเราถูกติดตั้งและรันขึ้นมาบนเครื่องที่ติดตั้งแอพ
เวอรชั่นเดิมของเราไวแลว (มีฐานขอมูลแลว) ซึ่งแอพเวอรชั่นใหม)คาดหวัง schema ที่
เปลี่ยนไปจากเดิม? เราตองแกไข schema ของฐานขอมูลที่มีอยู)แลวในตอนนั้น ให
สอดคลองกับการทํางานของแอพเวอรชั่นใหม) รวมถึงอาจตองโยกยายขอมูลดวย
การตอบคําถาม 2 ขอนี้จะทําไดโดย override เมธอด onCreate และเมธอด onUpgrade
ตามลําดับ
Hands On: ก% %) Helper Class
สมมติตองการเตรียมฐานขอมูลในแอพไวสําหรับเก็บชื่อและเบอรโทรติดต)อของบุคคลต)างๆ
เราจะสราง helper class ซึ่งเป/นซับคลาสของ SQLiteOpenHelper ดังนี้ (ใน Android Studio ให
สราง Java Class ใหม)ในแพคเกจเดียวกันกับแอคทิวิตี, ตั้งชื่อคลาสว)า DatabaseHelper)
package com.example.sqlitebasics;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DatabaseHelper extends SQLiteOpenHelper {

private static final String TAG = DatabaseHelper.class.getSimpleName();

Android: www.3bugs.com
private static final String DATABASE_NAME = "contacts.db";
private static final int DATABASE_VERSION = 1;

public static final String TABLE_NAME = "contacts";


public static final String COL_ID = "_id";
public static final String COL_NAME = "name";
public static final String COL_PHONE_NUMBER = "phone_number";

//
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {

คําสัง SQL ทีสมบูรณ์คือ


เทเบิล contacts
CREATE TABLE contacts (
_id INTEGER PRIMARY KEY AUTOINCREMENT
_id name phone_number
name TEXT,
phone_number TEXT
)

//
Log.d(TAG, "Creating table");
String SQL_CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "("
+ COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COL_NAME + " TEXT, "
+ COL_PHONE_NUMBER + " TEXT" + ")";
db.execSQL(SQL_CREATE_TABLE);

//
Log.d(TAG, "Inserting initial data");
ContentValues cv = new ContentValues();

cv.put(COL_NAME, " ");


cv.put(COL_PHONE_NUMBER, "111-111-1111");
db.insert(TABLE_NAME, null, cv);

Android: www.3bugs.com
cv.put(COL_NAME, " ");
cv.put(COL_PHONE_NUMBER, "222-222-2222");
db.insert(TABLE_NAME, null, cv);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String msg = "Upgrading database from version " + oldVersion + " to " +
newVersion;
Log.d(TAG, msg);

// ก
}
}

ก)อนอื่นใหสังเกตว)า เราเก็บชื่อและเวอรชั่นฐานขอมูล ชื่อเทเบิล และชื่อคอลัมนต)างๆไวใน


ตัวแปรแบบค)าคงที่ (constant) เพื่อใหง)ายต)อการ maintain โคด นอกจากนี้สําหรับชื่อเทเบิลและชื่อ
คอลัมน เรายังประกาศเป/น public เพื่อใหเรียกใชจากคลาสอื่นๆไดดวย ซึ่งจะเห็นต)อไปตอนที่อ)าน/
เขียนขอมูลในฐานขอมูล
การสรางซับคลาสของ SQLiteOpenHelper นั้น อย)างนอยที่สุดจะตอง implement 3 เมธอด
ไดแก)
คอนสตรัคเตอร ใหเรียกต)อไปยังคอนสตรัคเตอรของ SQLiteOpenHelper (super) โดย
ระบุอารกิวเมนต 4 ตัวคือ คอนเท็กซ (เช)น แอคทิวิตี), ชื่อฐานขอมูล, cursor factory
(โดยทั่วไปจะกําหนดค)า null) และเวอรชั่นของฐานขอมูลเป/นเลขจํานวนเต็ม ตามลําดับ

( &'BกC)'?& !$
% $&DB(@ (# E

( &'BกC) 4? F @ A# cursor factory & ) ? F @ A#

Android: www.3bugs.com
ในที่นี้คอนเท็กซที่ส)งให SQLiteOpenHelper เอามาจากพารามิเตอรของ DatabaseHelper
อีกที ซึ่งเราจะส)งค)าใหพารามิเตอรนี้ตอนที่สรางออบเจ็คของคลาส DatabaseHelper
ขึ้นมา
เมธอด onCreate แอนดรอยดจะมาเรียกเมธอดนี้เมื่อยังไม)มีฐานขอมูล และจําเป/นตอง
สรางขึ้นมา (เช)นตอนที่เราพยายามอ)านหรือเขียนขอมูล) โดยแอนดรอยดจะส)งออบเจ็ค
SQLiteDatabase มาให ซึ่งเป/นตัวแทนของฐานขอมูลว)างที่เพิ่งถูกสรางขึ้น หนาที่ของเราก็

คือทําการสรางเทเบิลและคอลัมนต)างๆในฐานขอมูล รวมถึงเตรียมขอมูลตั้งตนตามตองการ
โดยเรียกใชเมธอดบนออบเจ็ค SQLiteDatabase ที่ส)งมานี้
ก onCreate
ก F @ #A K'?
! " # $% ; )&L? @ME
call

Android: www.3bugs.com
ในที่นี้สรางเทเบิล 1 เทเบิลชื่อ contacts โดยใชเมธอด execSQL บนออบเจ็ค
SQLiteDatabase และระบุอารกิวเมนตเป/นคําสั่งในภาษา SQL ที่ใชสรางเทเบิล ซึ่งคําสั่ง

SQL ที่สมบูรณ (หลังจากแทนค)าคงที่ต)างๆลงไปแลว) คือ


CREATE TABLE contacts(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT,
phone_number TEXT)

คําสั่ง SQL ขางตนจะสรางเทเบิลชื่อ contacts ที่ประกอบดวย 3 คอลัมนคือ


คอลัมน _id เป/นชนิดเลขจํานวนเต็ม โดยกําหนดเป/น primary key ของเทเบิล (ค)าใน
คอลัมนนี้ของแถวต)างๆจะซ้ํากันไม)ได) และใหฐานขอมูลใส)ค)าใหอัตโนมัติเมื่อมีการเพิ่ม
แถวขอมูลลงในเทเบิล โดยใชค)าที่เพิ่มขึ้นทีละ 1
คอลัมน name เป/นชนิดขอความ (สตริง)
คอลัมน phone_number เป/นชนิดขอความ (สตริง)
นอกจากการสรางเทเบิลแลว เรายังเพิ่มขอมูล 2 ชุด (2 แถว) ลงไปดวย เพื่อใหเป/นขอมูล
ตั้งตนของฐานขอมูล
เมธอด onUpgrade แอนดรอยดจะมาเรียกเมธอดนี้ถาหากมีฐานขอมูลอยู)แลว และเวอรชั่น
ของฐานขอมูลที่มีอยู)นอยกว)า (เก)ากว)า) เลขเวอรชั่นที่เราระบุใหกับคอนสตรัคเตอรของ
SQLiteOpenHelper โดยแอนดรอยดจะส)งออบเจ็ค SQLiteDatabase ซึ่งเป/นตัวแทนของ

ฐานขอมูลเดิม, เลขเวอรชั่นเดิม และเลขเวอรชั่นใหม)มาให เพื่อใหเราตัดสินใจว)าควร


ปรับเปลี่ยน schema อย)างไร
รูปต)อไปนี้ สมมติว)าฐานขอมูลเดิมเป/นเวอรชั่น 1 และผูใชติดตั้งแอพเวอรชั่นใหม)ของเรา ซึ่ง
ในโคดระบุเวอรชั่นของฐานขอมูลเป/น 3

Android: www.3bugs.com
ก onUpgrade
ก ,
" ! , -./ ก

call F @ A#& 1 3

F @ #A &
& )? 1

ตัวอย)างนี้ไม)ไดทําอะไรใน onUpgrade นอกจากพิมพ log message ออกมา แต)ในการ


พัฒนาจริงเราอาจแกไขโครงสรางของเทเบิลโดยใชคําสั่ง ALTER ในภาษา SQL ยกตัวอย)าง
เช)น ถาพัฒนาแอพออกไปแลว 3 เวอรชั่น ดังนี้ (สมมติกําหนดเวอรชั่นฐานขอมูลตาม
เวอรชั่นของแอพ)
เวอรชั่น 1 มีคอลัมนสําหรับเก็บชื่อและเบอรโทรศัพท
เวอรชั่น 2 เพิ่มคอลัมนสําหรับเก็บวันเวลาที่ขอมูลถูกบันทึกลงฐานขอมูล
เวอรชั่น 3 เพิ่มคอลัมนสําหรับเก็บอีเมลแอดเดรส
เราจะเขียนโคดในเมธอด onUpgrade ของแอพเวอรชั่น 3 ดังนี้
// ! ก" # 1 ก% " " &ก
if (oldVersion == 1) {
db.execSQL("ALTER TABLE " + TABLE_NAME
+ " ADD COLUMN save_date DATE");
}

// ! ก" # 1 2 ก% '
if (oldVersion <= 2) {
db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN email TEXT");
}

Android: www.3bugs.com
จากโคด ถาหากฐานขอมูลเดิมเป/นเวอรชั่น 1 จะทํา if ทั้งสองบล็อค คือเพิ่มทั้งคอลัมน
วันเวลาและอีเมลแอดเดรส แต)หากฐานขอมูลเดิมเป/นเวอรชั่น 2 จะทําเฉพาะ if อันหลัง
คือเพิ่มคอลัมนอีเมลแอดเดรสเท)านั้น (ส)วนคอลัมนวันเวลาควรจะตองถูกเพิ่มไวแลวโดย
onUpgrade ของแอพเวอรชั่น 2)

การอัพเกรดฐานข้อมูลต้องตระหนักว่าผูใ้ ช้อาจไม่ได้ตดิ ตัง0 แอพมาทีละเวอร์ชนตามลํ


ั+ าดับ แต่อาจ
ติดตัง0 เวอร์ชนั + 1 แล้วข้ามมาเวอร์ชนั + 3 เลยโดยไม่ผา่ นเวอร์ชนั + 2 มาก่อน

นอกจากนี้ยังมีเมธอดของ SQLiteOpenHelper อีก 2 เมธอดที่เราสามารถ override ได แต)ไม)


บังคับ ไดแก)
เมธอด onOpen จะถูกแอนดรอยดเรียกเมื่อมีการเปeดฐานขอมูลนี้ขึ้นมา (ตอนเรียกเมธอด
getReadableDatabase หรือ getWritableDatabase ดังที่จะอธิบายในหัวขอถัดไป)

ดังนั้นถาตองการใหแอพทํางานบางอย)างในจังหวะที่ฐานขอมูลถูกเปeด ก็ให override


เมธอดนี้
เมธอด onDowngrade (สําหรับแอนดรอยด 3.0 ขึ้นไป) จะถูกเรียกเมื่อเวอรชั่นของ
ฐานขอมูลที่มีอยู)มากกว)า (ใหม)กว)า) เลขเวอรชั่นที่ระบุใหกับคอนสตรัคเตอรของ
SQLiteOpenHelper ซึ่งตรงขามกับ onUpgrade นั่นเอง

ก% 45)% Helper Class


การใชงาน helper class ซึ่งในกรณีของเราคือคลาส DatabaseHelper นั้น ใหสรางอินสแทนซ
(ออบเจ็ค) ของมันขึ้นมา ❶ หลังจากนั้นเมื่อตองการเขาถึงฐานขอมูล ใหเรียกเมธอด
getReadableDatabase หรือ getWritableDatabase บนออบเจ็คนั้น ❷ ก็จะไดตัวฐานขอมูล

(ออบเจ็ค SQLiteDatabase) สําหรับนํามาคิวรีหรือแกไขเพิ่มเติมขอมูลต)อไป ดังรูป

Android: www.3bugs.com
(#
SQLiteOpenHelper

extend
(inherit)
(# instantiate $&DB(
DatabaseHelper DatabaseHelper

getReadableDatabase getWritableDatabase
Helper Class
7/ # $%
(89: # return
SQLiteOpenHelper) rawQuery $&DB( ", 7
execSQL SQLiteDatabase ? :@A B, :?
", กC A
query delete
insert update

ในสถานการณปกติ ทั้งเมธอด getReadableDatabase และ getWritableDatabase จะ


ส)งคืนฐานขอมูลที่สามารถอ)านและเขียนไดเหมือนกันทั้งสองเมธอด ดังนั้นความเขาใจที่ว)า "เมธอด
getReadableDatabase จะส)งคืนฐานขอมูลที่อ)านได แต)เขียนไม)ได" จึงไม,ถูกตอง (ผูเขียนเองก็เคย

เขาใจแบบนั้น)
อย)างไรก็ตาม เมื่อเกิดปhญหา เช)น หน)วยความจํา (storage) เต็มหรือใกลเต็ม จะมีความ
แตกต)างระหว)างสองเมธอดนี้ โดยเมธอด getReadableDatabase จะส)งคืนฐานขอมูลที่อ)านได
อย)างเดียว (read-only) ในขณะที่เมธอด getWritableDatabase จะเกิดขอผิดพลาด ดังนั้นหากเรา
ตองการแค)เพียงอ)านขอมูลจากฐานขอมูล โดยไม)มีการเขียน (เพิ่ม/แกไข/ลบ) แลวล)ะก็ การเขาถึง
ฐานขอมูลดวยเมธอด getReadableDatabase จึงเป/นวิธีที่ปลอดภัยกว)า
การเรียกเมธอด getReadableDatabase หรือ getWritableDatabase จะทําใหฐานขอมูลถูก
สรางขึ้นกรณีที่ยังไม)มีฐานขอมูล (ซึ่งแอนดรอยดจะเรียกมายังเมธอด onCreate) หรือหากมีฐานขอมูล
แลวแต)เป/นเวอรชั่นเก)า ก็จะเรียกมายังเมธอด onUpgrade ดังที่อธิบายแลว พูดอีกอย)างคือ เมธอด

Android: www.3bugs.com
onCreate และ onUpgrade จะทํางานตอนที่เราเรียกเมธอด getReadableDatabase หรือ
getWritableDatabase นั่นเอง
Hands On: ก% %) 6, ) Helper Class
สําหรับแอพที่มีเพียงแอคทิวิตี (หนาจอ) เดียว เรามักจะสรางออบเจ็คของ helper class (ขอ
เรียกออบเจ็คนี้ว)า helper) ตอนที่แอคทิวิตีถูกสรางขึ้นมา นั่นก็คือในเมธอด onCreate ของแอคทิวิตี
แลวเก็บ helper ไวในตัวแปรระดับคลาสของแอคทิวิตี เพื่อใหทุกเมธอดในแอคทิวิตีมาเรียกใชได โดย
ไม)ตองสราง helper ใหม)ทุกครั้งที่ตองการทํางานกับฐานขอมูล
นอกจากนี้ตอนที่แอคทิวิตีกําลังจะถูกทําลาย เราก็จะเรียกเมธอด close ของ helper เพื่อปeด
ฐานขอมูลที่อาจเปeดอยู) อย)างไรก็ตาม จริงๆแลวการเรียกเมธอด close นี้ไม)ใช)เรื่องจําเป/น เพราะ
แอนดรอยดจะปeดฐานขอมูลใหเองอยู)แลวตอนที่มัน kill โปรเซสของแอพ
package com.example.sqlitebasics;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

private DatabaseHelper mHelper;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mHelper = new DatabaseHelper(this);


}

@Override
protected void onDestroy() {
super.onDestroy();

mHelper.close();
}
}

Android: www.3bugs.com
ใหสังเกตว)าเราสราง helper โดยระบุ this เป/นอารกิวเมนต ซึ่งก็คือการส)งแอคทิวิตีปhจจุบัน
(อินสแทนซของ MainActivity) ไปใหคอนสตรัคเตอรของ DatabaseHelper เนื่องจากเราออกแบบให
DatabaseHelper รับคอนเท็กซเขามา (เพื่อส)งต)อให SQLiteOpenHelper อีกที ดังที่อธิบายแลว) ซึ่ง

แอคทิวิตีคือคอนเท็กซชนิดหนึ่ง (MainActivity ของเราสืบทอดมาจาก AppCompatActivity และ


AppCompatActivity มี Context เป/นคลาสบรรพบุรุษ ดังรูป)

http://developer.android.com/reference/android/support/v7/app/AppCompatActivity.html

ก% % + %ก*% +
เมื่อพูดถึงการทํางานกับฐานขอมูล สิ่งที่เรามักจะทําบ)อยที่สุดก็คือการอ)านหรือดึงขอมูล
ออกมาใชงาน ซึ่งบ)อยครั้งจะมีการระบุเงื่อนไขเพื่อคัดเลือกเฉพาะขอมูลที่ตรงตามเงื่อนไขนั้น เช)น
พนักงานที่มีอายุงานมากกว)า 10 ปW หรือรายการสั่งซื้อที่มียอดรวมมากกว)า 100,000 บาท เป/นตน
การอ)านขอมูลจากฐานขอมูลจะทําไดโดยใชเมธอด query หรือเมธอด rawQuery
7 & query
วิธีหนึ่งในการอ)านขอมูลจากฐานขอมูล SQLite ก็คือการใชเมธอด query บนออบเจ็ค
SQLiteDatabase เมธอดนี้จะสรางประโยคคําสั่ง SELECT ในภาษา SQL (เรียกว)า คิวรี) ขึ้นจากค)าที่เรา

ระบุใหพารามิเตอรต)างๆของเมธอด เช)น โคดต)อไปนี้จะอ)านขอมูลทุกคอลัมนและทุกแถวจากเทเบิล


contacts ในฐานขอมูลตัวอย)างของเรา (ความจริงคือโคดบรรทัดเดียว แต)ขอแยกเป/นหลายบรรทัด

เพื่อใหดูง)าย)

Android: www.3bugs.com
Cursor cursor = db.query(
DatabaseHelper.TABLE_NAME, ❶
allColumns, ❷
null, ❸
null, ❹
null, ❺
null, ❻
null ❼
);

ตัวแปร db ในที่นี้คือออบเจ็ค SQLiteDatabase ที่ไดมาจากการเรียกเมธอด


getWritableDatabase บน helper ซึ่งอีกสักครู)จะแสดงโคดทั้งหมดใหคุณเห็น แต)ตอนนี้ผูเขียนขอ

โฟกัสไปที่เมธอด query ก)อน


ความหมายของพารามิเตอรต)างๆของเมธอด query
❶ ค)าสตริงระบุชื่อเทเบิลที่เราตองการอ)านขอมูล
❷ อารเรยของสตริง (String[]) ซึ่งระบุชื่อคอลัมนต)างๆที่เราตองการขอมูล เราอาจ
ระบุแค)บางคอลัมนหรือทุกคอลัมนก็ได (ถาตองการทุกคอลัมน วิธีง)ายๆคือใหระบุ
ค)า null)
ในที่นี้ตัวแปร allColumns คืออารเรยที่เก็บชื่อคอลัมนทั้งหมดของเทเบิล
contacts ไว
String[] allColumns = {
DatabaseHelper.COL_ID,
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER
};

❸ ค)าสตริงระบุเงื่อนไขของแถวขอมูลที่ตองการ เทียบเท)าส)วน WHERE ในภาษา SQL,


หากระบุ null หมายถึงใหเลือกมาทุกแถว
❹ อารเรยของสตริง ใชร)วมกับ ❸ โดยกรณีที่เราระบุเครื่องหมาย ? ลงใน ❸
แอนดรอยดจะนําค)าต)างๆจากอารเรยนี้แทนที่ ? ใหตามลําดับ
❺ ค)าสตริงระบุวิธีจัดกลุ)มใหกับแถวขอมูลที่เลือกมา เทียบเท)า GROUP BY ในภาษา SQL

Android: www.3bugs.com
❻ ค)าสตริง ใชร)วมกับ ❺ เพื่อระบุเงื่อนไขของกลุ)มขอมูลที่จะเลือกมา เทียบเท)า
HAVING ในภาษา SQL

❼ ค)าสตริงระบุวิธีจัดเรียงแถวขอมูล เทียบเท)า ORDER BY ในภาษา SQL


7 & rawQuery
การอ)านขอมูลจากฐานขอมูลยังทําไดอีกวิธีหนึ่ง โดยใชเมธอด rawQuery ซึ่งเป/นเมธอดบน
ออบเจ็ค SQLiteDatabase เช)นกัน เมธอดนี้จะใหเราระบุคําสั่งในภาษา SQL เองโดยตรง เหมาะ
สําหรับคนที่คุนเคยกับภาษา SQL เป/นอย)างดี
ขอดีของการใชเมธอดนี้คือ เราสามารถระบุคําสั่งใดในภาษา SQL ก็ได ตราบใดที่คําสั่งนั้นมี
syntax ถูกตองและใหผลลัพธเป/น result set ดังนั้นจึงสามารถใช join หรือ sub-select ไดโดยไม)มี
ปhญหา
ตัวอย)างการใชเมธอด rawQuery อ)านขอมูลทั้งหมดจากเทเบิล contacts ในฐานขอมูลตัวอย)าง
ของเรา
String sqlSelect = "SELECT * FROM " + DatabaseHelper.TABLE_NAME;
Cursor cursor = db.rawQuery(sqlSelect, null);

เมธอด rawQuery มีพารามิเตอร 2 ตัว ตัวแรกคือคิวรี (ประโยคคําสั่ง SELECT ในภาษา SQL)


ส)วนตัวที่ 2 คืออารเรยของสตริง จะใชร)วมกับพารามิเตอรตัวแรก โดยกรณีที่เราระบุเครื่องหมาย ? ลง
ในส)วน WHERE หรือ ORDER BY ของคิวรี แอนดรอยดจะนําค)าต)างๆจากอารเรยนี้แทนที่ ? ในคิวรีให
ตามลําดับ เช)น โคดต)อไปนี้จะอ)านมาเฉพาะแถวขอมูลที่มีคอลัมน name เป/นคําว)า "ณัฐปภัสร"
String sqlSelect = "SELECT * FROM " + DatabaseHelper.TABLE_NAME +
" WHERE " + DatabaseHelper.COL_NAME + "=?";
String[] args = { " " };
Cursor cursor = db.rawQuery(sqlSelect, args);

จากโคด เมื่อแทนค)าคงที่ TABLE_NAME และ COL_NAME แลว ตัวแปร sqlSelect จะมีค)าเป/น


สตริง
SELECT * FROM contacts WHERE name=?

Android: www.3bugs.com
จากนั้นเมื่อนํามาระบุในเมธอด rawQuery ก็จะทําใหเครื่องหมาย ? ถูกแทนดวยค)าสตริง
" " จากอารเรย args และเราจะไดคิวรีที่สมบูรณ

Hands On: ก% % +& 7 & query ' rawQuery


เราจะอ)านขอมูลทุกแถวและทุกคอลัมนจากเทเบิล contacts โดยเพิ่มการประกาศตัวแปร mDb
อีกตัวหนึ่งที่ส)วนประกาศของแอคทิวิตี และเพิ่มโคดในเมธอด onCreate ของแอคทิวิตี ดังนี้
public class MainActivity extends AppCompatActivity {

private DatabaseHelper mHelper;


private SQLiteDatabase mDb;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mHelper = new DatabaseHelper(this);


mDb = mHelper.getWritableDatabase();

String[] allColumns = {
DatabaseHelper.COL_ID,
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER
};
Cursor cursor = mDb.query(DatabaseHelper.TABLE_NAME, allColumns, null,
null, null, null, null);
}
...
}

ขางบนใชเมธอด query ในการอ)านขอมูล แต)หากเปลี่ยนมาใชเมธอด rawQuery จะเขียนได


ดังนี้
public class MainActivity extends AppCompatActivity {

private DatabaseHelper mHelper;


private SQLiteDatabase mDb;

Android: www.3bugs.com
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mHelper = new DatabaseHelper(this);


mDb = mHelper.getWritableDatabase();

String sqlSelect = "SELECT * FROM " + DatabaseHelper.TABLE_NAME;


Cursor cursor = mDb.rawQuery(sqlSelect, null);
}
...
}

+ กก , < = <
ทั้งเมธอด query และ rawQuery จะส)งคืนเคอรเซอร (ออบเจ็ค Cursor) กลับมาใหเรา
เคอรเซอรนั้นถาอธิบายง)ายๆก็คือออบเจ็คที่เก็บผลลัพธ (result set) ของคิวรีไว ซึ่งก็คือแถวและ
คอลัมนทั้งหมดที่ไดจากฐานขอมูลตามคําสั่งของคิวรี

1 L &# 111-111-1111
2 "F[\ ) 222-222-2222

&( )&C )

เนื่องจาก result set อาจมีขนาดใหญ) ทําใหใชหน)วยความจํามาก ดังนั้นหลังจากใชงาน


เคอรเซอรแลวจึงควรปeดทุกครั้งโดยเรียกเมธอด close บนเคอรเซอร
Cursor cursor = mDb.query(DatabaseHelper.TABLE_NAME, allColumns, null, null,
null, null, null);

// ( )ก * #
cursor.close(); // +, *

Android: www.3bugs.com
เมื่อตองการอ)านขอมูลจากเคอรเซอรมาใชงาน (เช)นแสดงผลบนจอ) เราอาจใชวิธีเขาถึงแถว
ขอมูลแต)ละแถวในเคอรเซอรเองโดยตรง หรืออาจใช CursorAdapter มาช)วยก็ได
ก% % + %ก , < = <>& )
ขอย้ําอีกครั้งว)า ขอมูลที่อยู)ในเคอรเซอร คือ result set ซึ่งมีลักษณะเป/นแถวและคอลัมน
เหมือนกับเทเบิลในฐานขอมูล แต)ขอมูลนี้จะเป/น subset ของขอมูลในเทเบิล (ไม)พูดถึงการอ)านขอมูล
จากหลายเทเบิลกรณีฐานขอมูลมีมากกว)า 1 เทเบิล) เราสามารถหาจํานวนแถวใน result set ไดโดย
เรียกเมธอด getCount บนเคอรเซอร
int rowCount = cursor.getCount();

โดยทั่วไปเราจะอ)าน result set จากเคอรเซอรมาทีละแถว โดยภายในเคอรเซอรจะมีตัวชี้


สําหรับชี้ไปยังแถวขอมูลหนึ่งๆ ซึ่งตอนเริ่มตน (ตอนที่เมธอด query หรือ rawQuery ส)งคืนเคอรเซอร
มาให) ตัวชี้นี้จะชี้ไปที่ตําแหน)ง "ก)อน" แถวขอมูลแรก ดังรูป (รูปนี้สมมติว)า result set คือขอมูลทุกแถว
และทุกคอลัมนจากเทเบิล contacts ในฐานขอมูลตัวอย)างของเรา)

1 L &# 111-111-1111
2 "F[\ ) 222-222-2222

&( )&C )

เมื่อตัวชี้อยู)ที่ตําแหน)งดังกล)าว เราสามารถใชเมธอด moveToNext หรือ moveToFirst เพื่อ


ขยับตัวชี้ไปที่แถวขอมูลแรกใน result set ดังรูปถัดไป

Android: www.3bugs.com
1 L &# 111-111-1111
2 "F[\ ) 222-222-2222

&( )&C )

จากนั้นเราจะอ)านขอมูลแต)ละคอลัมนจากแถวนั้นโดยใชเมธอด เช)น getString, getInt


(จะอธิบายรายละเอียดอีกที) แลวเรียกเมธอด moveToNext เพื่อขยับตัวชี้ไปยังแถวถัดไป แลวอ)าน
ขอมูลแต)ละคอลัมน แลวขยับไปแถวถัดไป แลวอ)านขอมูลแต)ละคอลัมน ฯลฯ ซ้ําอย)างนี้ไปเรื่อยๆจน
ครบทุกแถว
หากตองการรูว)าตัวชี้อยู)ที่ตําแหน)ง "หลัง" แถวขอมูลสุดทายหรือยัง ใหใชเมธอด isAfterLast
ซึ่งจะส)งคืนค)าตรรกะ true หรือ false มาให

1 L &# 111-111-1111 & ^ isAfterLast


2 "F[\ ) 222-222-2222 D!(4 ( true

&( )&C )

นอกจากนี้ เมธอด moveToNext ที่ใชขยับตัวชี้ไปแถวถัดไป จะส)งคืนค)าตรรกะ false ถาหาก


มันขยับตัวชี้ผ)านแถวสุดทายไปแลว (ตัวชี้ไปอยู)ที่ตําแหน)ง "หลัง" แถวสุดทายแลว) และจะส)งคืนค)า
true ถาหากยังไม)ผ)านแถวสุดทาย ดังนั้นเราสามารถใชโครงสราง loop ต)อไปนี้ เพื่ออ)านขอมูลจากทุก

แถวใน result set โดยเริ่มตั้งแต)แถวแรกไปตามลําดับจนถึงแถวสุดทาย


while (cursor.moveToNext()) {

// ( ( - '!" & -
}

Android: www.3bugs.com
ลูปคําสั่ง while ขางตนจะทํางานไดอย)างลงตัว โดยตอนเริ่มตนจะขยับตัวชี้จากตําแหน)ง
"ก)อน" แถวขอมูลแรกไปยังแถวขอมูลแรก แลวค)อยทําโคดภายในลูปเพื่ออ)านขอมูลแต)ละคอลัมน และ
เมื่อวนซ้ําไปเรื่อยๆจนตัวชี้ถูกขยับไปอยู)ที่ตําแหน)ง "หลัง" แถวสุดทายแลว เมธอด moveToNext จะคืน
ค)า false ทําใหเงื่อนไขของ while เป/น false และออกจากลูปทันที โคดภายในลูปจึงไม)ถูกทําอีก
สําหรับการอ)านขอมูลแต)ละคอลัมนจะใชเมธอด getString, getInt, getShort, getLong,
getFloat, getDouble, getBlob ขึ้นอยู)กับว)า เราจะอ)านขอมูลในคอลัมนนั้นมาเป/นชนิดขอมูลใดใน

ภาษาจาวา ซึ่งปกติเราจะดูที่ชนิดขอมูลของคอลัมน (ชนิดขอมูลใน SQLite ตามที่เรากําหนดตอนสราง


เทเบิล) ถาเป/นชนิด TEXT ก็ใชเมธอด getString, ถาเป/นชนิด INTEGER ก็ใช getInt, getShort หรือ
getLong เป/นตน

SQLite มีชนิดข้อมูลแบบเลขจํานวนเต็มเพียงชนิดเดียวคือ INTEGER ซึง+ ใช้เนื0อทีเ+ ก็บข้อมูล 1, 2,


3, 4, 6 หรือ 8 ไบต์ ขึน0 อยูก่ บั ขนาดของค่าทีเ+ ก็บลงไป ดังนัน0 เวลาอ่านข้อมูลจากคอลัมน์ชนิด
INTEGER ในฐานข้อมูล SQLite จึงต้องเลือกใช้เมธอดให้เหมาะสม ซึง+ เมธอด getInt น่ าจะ
เพียงพอสําหรับแอพทัวๆไป + เพราะชนิดข้อมูล int ในจาวาสามารถเก็บค่าได้ตงั 0 แต่ -231 ถึง
31
2 -1 (ลบ 2 พันล้านถึง 2 พันล้าน โดยประมาณ)
สําหรับช่วงค่าทีช+ นิดข้อมูลต่างๆในภาษาจาวาสามารถเก็บได้ ให้ดทู +ี docs.oracle.com/
javase/tutorial/java/nutsandbolts/datatypes.html

เมธอด getXxx มีพารามิเตอร 1 ตัวชนิด int สําหรับระบุ index ของคอลัมนที่เราตองการอ)าน


ขอมูล (คอลัมนแรกคือ index 0) แต)หากตองการอ)านขอมูลโดยระบุชื่อคอลัมน ใหใชเมธอด
getColumnIndex เพื่อหา index จากชื่อคอลัมนก)อน (คิดง)ายๆว)าแปลงชื่อคอลัมนไปเป/น index) แลว

ค)อยนําค)าที่ไดไประบุใหเมธอด getXxx อีกที เช)น โคดต)อไปนี้จะอ)านขอมูลจากคอลัมน _id ในเทเบิล


contacts ของเรา มาเก็บลงตัวแปร id
int id = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.COL_ID));

Hands On: ก% % + %ก , < = <>& ) &)?


จาก Hands On ที่แลว เราคิวรีฐานขอมูลดวยเมธอด query หรือ rawQuery ซึ่งไดผลลัพธเป/น
เคอรเซอรที่เก็บ result set ไว ดังนั้นขั้นตอนถัดไป เราตองอ)าน result set จากเคอรเซอรเพื่อนําขอมูล
มาใชงานตามตองการ ในที่นี้จะแสดงออกมาบนจอโดยใส)ขอมูลลงใน TextView

Android: www.3bugs.com
1 ก)อนอื่นกําหนด layout ของหนาจอ (ไฟล activity_main.xml) ใหมี TextView 1 อันชื่อ
textView

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">

<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World"
android:textSize="16sp"/>

</RelativeLayout>

2 เพิ่มโคดในเมธอด onCreate ของแอคทิวิตี


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mHelper = new DatabaseHelper(this);


mDb = mHelper.getWritableDatabase();

String[] allColumns = {
DatabaseHelper.COL_ID,
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER
};
Cursor cursor = mDb.query(DatabaseHelper.TABLE_NAME, allColumns, null,
null, null, null, null);

Android: www.3bugs.com
String text = "";
while (cursor.moveToNext()) {
// ( '(. ก% "'+ ( -
int id = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.COL_ID));
String name = cursor.getString(cursor.getColumnIndex(DatabaseHelper
.COL_NAME));
String phoneNumber = cursor.getString(cursor.getColumnIndex
(DatabaseHelper.COL_PHONE_NUMBER));

// ) +' ' ( .'!" ' " ก% /ก'!" " 0" "'+ "
text += String.format("%d, %s, %s\n", id, name, phoneNumber);
}
// ' TextView
((TextView) findViewById(R.id.text_view)).setText(text);
// # * %)' " +, * /ก
cursor.close();
}

3 สั่งรันแอพ จะไดดังรูป

Android: www.3bugs.com
และจะมีขอความใน logcat ดังรูป (ในที่นี้กําหนด filter ใหแสดงเฉพาะ log message ที่มี tag
เป/นคําว)า DatabaseHelper)

ก% % + %ก , < = <& CursorAdapter


นอกจากการเขาถึงเคอรเซอรโดยตรงแลว เรายังมีวิธีนําขอมูลจากเคอรเซอรมาแสดงผลอีกวิธี
หนึ่ง โดยการผูก (bind) เคอรเซอรเขากับวิวที่เป/น AdapterView เช)น ListView เพื่อแสดงขอมูล
ออกมาที่ AdapterView นั้น (วิวใดก็ตามที่เป/นซับคลาสของ AdapterView สามารถใชไดหมด ซึ่ง
ListView คือหนึ่งในนั้น)

การผูกเคอรเซอรกับ ListView (หรือ AdapterView ใดๆ) เขาดวยกัน จะใช CursorAdapter


เป/นตัวกลาง ดังรูป โดยวิธีที่ง)ายที่สุดก็คือใช SimpleCursorAdapter ซึ่งเป/นซับคลาสของ
CursorAdapter อีกที

AdapterView CursorAdapter &( )&C )


& ListView & SimpleCursorAdapter

SimpleCursorAdapter จะอ)านแถวขอมูลหนึ่งๆจากเคอรเซอรมาแสดงเป/นไอเท็มหนึ่งๆใน
ListView โดยเราตองเตรียม layout file ที่กําหนด layout ใหกับไอเท็มเหล)านี้ (ไฟลเดียวใชกับทุกๆ

ไอเท็ม ดังนั้นไอเท็มใน ListView จะมี layout เหมือนกันหมด แต)ขอมูลแตกต)างกัน)

Android: www.3bugs.com
text1
text2
layout
1 L &# 111-111-1111
2 "F[\ ) 222-222-2222
ListView text1
text2 &( )&C )
layout
android.R.layout.simple_list_item_2

จากรูป การทํางานของ SimpleCursorAdapter โดยคร)าวๆคือ มันจะนําขอมูลแต)ละคอลัมน


ของแถวหนึ่งๆใส)ลงแต)ละวิวใน layout เป/นคู)ๆตามที่เรากําหนด ❶ แลวจึงส)ง layout (ที่ใส)ขอมูลแลว)
ไปให ListView เพื่อแสดงผลออกมาเป/น 1 ไอเท็ม ❷ SimpleCursorAdapter จะทําแบบนี้กับแถว
ขอมูลทุกแถวในเคอรเซอรใหอัตโนมัติ เราไม)ตองขยับตําแหน)งตัวชี้ในเคอรเซอรเอง
การใชงาน SimpleCursorAdapter มี 2 ขั้นตอนหลักๆ
1 สรางออบเจ็ค SimpleCursorAdapter (ขอแยกเป/นหลายบรรทัดเพื่อใหดูง)าย)

mAdapter = new SimpleCursorAdapter(


this, ❶
android.R.layout.simple_list_item_2, ❷
cursor, ❸
showColumns, ❹
views, ❺
0 ❻
);

Android: www.3bugs.com
ความหมายของพารามิเตอรต)างๆ
❶ คอนเท็กซ เช)น แอคทิวิตี
❷ layout file ที่กําหนด layout ของแต)ละไอเท็มใน ListView (แต)ละแถวขอมูล)
ในที่นี้เลือกใช layout ที่แอนดรอยดเตรียมมาให (predefined) คือ
android.R.layout.simple_list_item_2 ซึ่งเป/น layout ที่มี TextView 2 อัน

วางเรียงในแนวตั้ง โดย ID ของ TextView ทั้งสองคือ text1 และ text2


❸ เคอรเซอร
❹ รายชื่อคอลัมนที่ตองการแสดงขอมูลออกมาใน ListView ในที่นี้ระบุตัวแปร
showColumns ซึ่งกําหนดค)าไวดังนี้

String[] showColumns = {
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER
};

❺ รายการวิวใน layout ซึ่งขอมูลจากคอลัมนต)างๆที่ระบุใน ❹ จะถูกนํามาใส)ลงใน


วิวเหล)านี้ตามลําดับ ในที่นี้ระบุตัวแปร views ซึ่งกําหนดค)าไวดังนี้
int[] views = {
android.R.id.text1,
android.R.id.text2
};

❻ flags ซึ่งเป/นเลขจํานวนเต็มที่กําหนดพฤติกรรมของ adapter (ไม)ขออธิบาย)


โดยทั่วไปจะระบุค)า 0 (ศูนย)
2 หลังจากสรางออบเจ็ค SimpleCursorAdapter แลว ก็นําไปกําหนดให ListView โดยใชเมธอด
setAdapter บน ListView นั้น

((ListView) findViewById(R.id.listView)).setAdapter(mAdapter);

Android: www.3bugs.com
Hands On: ก% &) + %ก , < = < ก %4 ListView >& 45
SimpleCursorAdapter
เราจะแกไขโคดจาก Hands On ที่แลวที่เป/นการเขาถึงขอมูลในเคอรเซอรโดยตรง มาเป/นการ
ใช SimpleCursorAdapter
1 แกไข layout โดยลบ TextView แลวเพิ่ม ListView เขามาแทน

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">

<ListView
android:id="@+id/list_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

</RelativeLayout>

2 ที่แอคทิวิตี ใหลบโคดที่เราเพิ่มในเมธอด onCreate ใน Hands On ที่แลว แลวพิมพโคดลงไป


ใหม)ดังนี้
public class MainActivity extends ActionBarActivity {

private DatabaseHelper mHelper;


private SQLiteDatabase mDb;
private SimpleCursorAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Android: www.3bugs.com
mHelper = new DatabaseHelper(this);
mDb = mHelper.getWritableDatabase();

String[] allColumns = {
DatabaseHelper.COL_ID,
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER
};
Cursor cursor = mDb.query(DatabaseHelper.TABLE_NAME, allColumns, null,
null, null, null, null);

// result set ).' ก


String[] showColumns = {
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER
};
// "" layout ).) (ก result set
int[] views = {
android.R.id.text1,
android.R.id.text2
};

// adapter
mAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2, cursor, showColumns, views, 0);
// ก adapter ก ListView
((ListView) findViewById(R.id.list_view)).setAdapter(mAdapter);
}

@Override
protected void onDestroy() {
super.onDestroy();

// +, *
mAdapter.getCursor().close();
mHelper.close();
}
}

Android: www.3bugs.com
สังเกตว)าเราไม)ไดปeดเคอรเซอรในเมธอด onCreate เหมือนอย)างโคดใน Hands On ที่แลว
เพราะเคอรเซอรจะถูกใชงานโดย adapter ตลอดเวลาที่ขอมูลถูกแสดงออกมาใน ListView
ดังนั้นเราจึงปeดเคอรเซอรตอนที่แอคทิวิตีกําลังจะถูกทําลาย คือในเมธอด onDestroy แทน
3 สั่งรันแอพ จะไดดังรูป

ก% ( กB C + 4 *% +
การดําเนินการกับขอมูลในฐานขอมูลนั้นมีอยู) 4 เรื่อง ไดแก) การสรางหรือเพิ่มขอมูลใหม), การ
อ)านขอมูลมาใชงาน, การแกไข/ปรับปรุงขอมูล และการลบขอมูล เราเรียกการดําเนินการทั้งสี่นี้รวมๆว)า
CRUD (create-read-update-delete)
ที่ผ)านมา เราไดเรียนรูวิธีการอ)านขอมูลจากฐานขอมูลแลว ดังนั้นในหัวขอนี้จะอธิบายการ
ดําเนินการอีก 3 เรื่องที่เหลือ คือ การเพิ่ม การแกไข และการลบ

Android: www.3bugs.com
7 & insert, update C delete
เราทราบแลวว)าการอ)านขอมูลจะใชเมธอด query บนออบเจ็ค SQLiteDatabase สําหรับการ
เพิ่ม แกไข และลบขอมูลนั้นจะใชเมธอด insert, เมธอด update และเมธอด delete ตามลําดับ ซึ่ง
เป/นเมธอดบนออบเจ็ค SQLiteDatabase เช)นเดียวกัน จะขออธิบายรายละเอียดไปทีละเมธอด
เมธอด insert
ใชเพิ่มแถวขอมูลใหม)ลงในเทเบิล ความจริงเราเคยใชเมธอดนี้มาแลวตอนที่เตรียมขอมูลตั้งตน
ใหกับฐานขอมูล (ภายในคลาส DatabaseHelper ซึ่งเป/น helper class ของเรา) แต)ครั้งนี้จะลอง
เรียกใชจากภายในแอคทิวิตีบาง เช)นถาตองการเพิ่มขอมูลผูติดต)อใหม)ชื่อ "มนัสนันท" ที่มีเบอรโทรคือ
333-333-3333 จะเขียนโคดไดดังนี้
ContentValues cv = new ContentValues();
cv.put(DatabaseHelper.COL_NAME, " ");
cv.put(DatabaseHelper.COL_PHONE_NUMBER, "333-333-3333");

mDb.insert( ContentValues
DatabaseHelper.TABLE_NAME, ❶
null, ❷ key value
cv ❸
name "มนัสนันท์"
);
phone_number "333-333-3333"
เมธอด insert มีพารามิเตอร 3 ตัว
❶ ค)าสตริงระบุชื่อเทเบิลที่จะเพิ่มแถวขอมูลลงไป
❷ (ในเอกสารของแอนดรอยดตั้งชื่อพารามิเตอรตัวนี้ว)า nullColumnHack) จะใชกรณี
เพิ่มแถวขอมูลว)าง (empty row) ลงในเทเบิล ซึ่งตองอธิบายเพิ่มเติมว)า SQLite ไม)
อนุญาตใหเพิ่มแถวขอมูลว)างได แต)จะตองมีการกําหนดค)าอย)างนอย 1 คอลัมน
เมธอด insert จึงใหเราระบุชื่อคอลัมนที่เป/น null ไดมาคอลัมนหนึ่ง และหากเรา
ระบุ ContentValues ว)างๆเป/นพารามิเตอรตัวที่ 3 เมธอด insert ก็จะเพิ่มแถว
ขอมูลใหม)โดยกําหนดค)า null ใหกับคอลัมนนั้น
❸ ออบเจ็ค ContentValues ซึ่งระบุชื่อและค)าที่เราตองการกําหนดใหกับคอลัมน
ต)างๆในแถวขอมูลใหม) ในที่นี้กําหนดค)าเฉพาะคอลัมน name และ

Android: www.3bugs.com
phone_number ส)วนคอลัมน _id นั้น SQLite จะกําหนดค)าใหอัตโนมัติ
อันเนื่องมาจากคุณสมบัติ AUTOINCREMENT ที่เราระบุตอนสรางเทเบิล

ContentValues เทเบิล contacts


key value _id name phone_number

name "มนัสนันท์"
phone_number "333-333-3333"

โดยทั่วไปเราไม)มีความจําเป/นตองเพิ่มแถวขอมูลว)างลงในเทเบิล ดั้งนั้นพารามิเตอรตัวที่ 2 นี้จึง


มักไม)ค)อยไดใช และเราจะกําหนดค)า null ใหมัน ดังเช)นในโคดตัวอย)างขางบน
เมธอด insert จะส)งคืนค)า ID ของแถวขอมูลใหม)กลับมาใหถาเพิ่มสําเร็จ หรือส)งคืนค)า -1 ถา
หากเกิดขอผิดพลาด
เมธอด update
ใชแกไข/ปรับปรุงขอมูลในเทเบิล โดยสามารถระบุคอลัมนและแถวที่ตองการแกไขได เช)น โคด
ต)อไปนี้จะเปลี่ยนเบอรโทรของ "พรอมเลิศ" เป/น 555-555-5555 (แกไขคอลัมน phone_number เป/น
ค)า "555-555-5555" เฉพาะแถวที่มีคอลัมน name เป/นค)า "พรอมเลิศ")
ContentValues cv = new ContentValues();
cv.put(DatabaseHelper.COL_PHONE_NUMBER, "555-555-5555");

mDb.update(
DatabaseHelper.TABLE_NAME, ❶
cv, ❷
DatabaseHelper.COL_NAME + "=?", ❸
new String[] { " " } ❹
);

เมธอด update มีพารามิเตอร 4 ตัว

Android: www.3bugs.com
❶ ค)าสตริงระบุชื่อเทเบิลที่จะแกไขขอมูล
❷ ออบเจ็ค ContenValues ซึ่งระบุชื่อและค)าใหม)ที่เราตองการกําหนดใหคอลัมน
ต)างๆ (ค)าเดิมในคอลัมนจะถูกแทนที่ดวยค)าจาก ContentValues นี้)
❸ ค)าสตริงระบุเงื่อนไขของแถวที่จะถูกแกไขขอมูล เทียบเท)าส)วน WHERE ในภาษา SQL
❹ อารเรยของสตริง ซึ่งค)าสตริงแต)ละค)าจะถูกนําไปแทนที่เครื่องหมาย ? (ถามี) ใน
❸ ตามลําดับ

เมื่อแทนค)าคงที่ DatabaseHelper.COL_NAME และแทนค)าสตริงจาก ❹ ลงใน ❸ เราจะได


เงื่อนไขของแถวขอมูลที่จะถูกแกไขเบอรโทรในตัวอย)างนี้คือ name=" "

เมธอด delete
ใชลบแถวขอมูลในเทเบิล โดยสามารถระบุเงื่อนไขของแถวที่ตองการลบได เช)น โคดต)อไปนี้จะ
ลบแถวที่มีเบอรโทรขึ้นตนดวย 333
mDb.delete(
DatabaseHelper.TABLE_NAME, ❶
DatabaseHelper.COL_PHONE_NUMBER + " LIKE ?", ❷
new String[] { "333%" } ❸
);

เมธอด delete มีพารามิเตอร 3 ตัว


❶ ค)าสตริงระบุชื่อเทเบิลที่จะลบแถวขอมูล
❷ ค)าสตริงระบุเงื่อนไขของแถวที่จะถูกลบ เทียบเท)าส)วน WHERE ในภาษา SQL,
ถาหากระบุ null จะลบทุกแถวในเทเบิล
❸ อารเรยของสตริง ซึ่งค)าสตริงแต)ละค)าจะถูกนําไปแทนที่เครื่องหมาย ? (ถามี) ใน
❷ ตามลําดับ

เมื่อแทนค)าคงที่ DatabaseHelper.COL_PHONE_NUMBER และแทนค)าสตริงจาก ❸ ลงใน ❷


เราจะไดเงื่อนไขของแถวขอมูลที่จะถูกลบในตัวอย)างนี้คือ phone_number LIKE "333%" โดย
เครื่องหมาย % ในภาษา SQL หมายถึงตัวอักษรใดๆกี่ตัวก็ได

Android: www.3bugs.com
7 & execSQL
อีกวิธีหนึ่งที่สามารถเพิ่ม แกไข และลบแถวขอมูลได นอกเหนือจากการใชเมธอด insert,
update และ delete ที่อธิบายแลว ก็คือการระบุประโยคคําสั่งในภาษา SQL โดยตรงใหกับเมธอด

execSQL บนออบเจ็ค SQLiteDatabase แต)นั่นหมายความว)าคุณจะตองเขียนภาษา SQL เป/น (ซึ่งไม)ได

ยากแต)อย)างใด)

นอกจากนี0 เมธอด execSQL ยังสามารถใช้จดั การ schema ของฐานข้อมูลได้อกี ด้วย ไม่วา่ จะ


เป็ นการสร้างเทเบิล แก้ไขโครงสร้างของเทเบิล ลบเทเบิล สร้างอินเด็กซ์ของฐานข้อมูล ฯลฯ
ซึง+ ถ้าดูในคลาส DatabaseHelper ก็จะพบว่าเมธอด execSQL นี0เองทีเ+ ราใช้สร้างเทเบิล
contacts ขึน 0 มาในฐานข้อมูล

ตัวอย่ างการเพิมข้ อมูล


ถาตองการเพิ่มผูติดต)อใหม)ชื่อ "มนัสนันท" ที่มีเบอรโทรคือ 333-333-3333 จะเขียน SQL ได
ดังนี้ (จริงๆเขียนต)อเนื่องกันไปในบรรทัดเดียวก็ได)
INSERT INTO contacts (name, phone_number)
VALUES (' ', '333-333-3333')

เราสามารถเขียนโคดจาวาที่ระบุ SQL ขางตนใหกับเมธอด execSQL ไดดังนี้ (สําหรับชื่อเทเบิล


และชื่อคอลัมน จะขอใชค)าคงที่แทนการระบุชื่อลงไปตรงๆ)
String sql = "INSERT INTO %s (%s, %s) VALUES ('%s', '%s')";
sql = String.format(
sql,
DatabaseHelper.TABLE_NAME,
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER,
" ",
"333-333-3333"
);
mDb.execSQL(sql);

Android: www.3bugs.com
จากโคด เมธอด String.format จะนําชื่อเทเบิล ชื่อคอลัมน และค)าที่เราตองการกําหนดให
คอลัมนเหล)านั้น แทนลงใน %s ในตัวแปร sql แลวนําสตริงผลลัพธ (คําสั่ง SQL ที่สมบูรณ) เก็บลง
ตัวแปร sql อีกครั้ง ก)อนนําไประบุใหเมธอด execSQL ในบรรทัดสุดทาย
คําสั่ง SQL ที่ส)งใหเมธอด execSQL เป/นเพียงค)าสตริงธรรมดา ดังนั้นเราอาจใชการเชื่อมต)อ
สตริงเพื่อสรางคําสั่ง SQL ที่สมบูรณแทนการใชเมธอด String.format ก็ได แต)จะทําใหโคดดูเขาใจ
ยากกว)า
ตัวอย่ างการแก้ ไขข้ อมูล
ถาตองการเปลี่ยนเบอรโทรของ "พรอมเลิศ" เป/น 555-555-5555 จะเขียน SQL ไดดังนี้ (จริงๆ
เขียนต)อเนื่องกันไปในบรรทัดเดียวก็ได)
UPDATE contacts
SET phone_number='555-555-5555'
WHERE name=' '

เราสามารถเขียนโคดจาวาที่ระบุ SQL ขางตนใหกับเมธอด execSQL ไดดังนี้ (สําหรับชื่อเทเบิล


และชื่อคอลัมน จะขอใชค)าคงที่แทนการระบุชื่อลงไปตรงๆ)
String sql = "UPDATE %s SET %s='%s' WHERE %s='%s'";
sql = String.format(
sql,
DatabaseHelper.TABLE_NAME,
DatabaseHelper.COL_PHONE_NUMBER,
"555-555-5555",
DatabaseHelper.COL_NAME,
" "
);
mDb.execSQL(sql);

จากโคด เมธอด String.format จะนําชื่อเทเบิล ชื่อคอลัมน และค)าต)างๆ แทนลงใน %s ใน


ตัวแปร sql แลวนําสตริงผลลัพธ (คําสั่ง SQL ที่สมบูรณ) เก็บลงตัวแปร sql อีกครั้ง ก)อนนําไประบุให
เมธอด execSQL ในบรรทัดสุดทาย

Android: www.3bugs.com
ตัวอย่ างการลบข้ อมูล
ถาตองการลบแถวที่มีเบอรโทรขึ้นตนดวย 333 จะเขียน SQL ไดดังนี้ (จริงๆเขียนต)อเนื่องกันไป
ในบรรทัดเดียวก็ได)
DELETE FROM contacts
WHERE phone_number LIKE '333%'

เราสามารถเขียนโคดจาวาที่ระบุ SQL ขางตนใหกับเมธอด execSQL ไดดังนี้ (สําหรับชื่อเทเบิล


และชื่อคอลัมน จะขอใชค)าคงที่แทนการระบุชื่อลงไปตรงๆ)
String sql = "DELETE FROM %s WHERE %s LIKE '%s'";
sql = String.format(
sql,
DatabaseHelper.TABLE_NAME,
DatabaseHelper.COL_PHONE_NUMBER,
"333%"
);
mDb.execSQL(sql);

จากโคด เมธอด String.format จะนําชื่อเทเบิล ชื่อคอลัมน และค)าสตริง "333%" แทนลงใน


%s ในตัวแปร sql แลวนําสตริงผลลัพธ (คําสั่ง SQL ที่สมบูรณ) เก็บลงตัวแปร sql อีกครั้ง ก)อนนําไป

ระบุใหเมธอด execSQL ในบรรทัดสุดทาย


Hands On: ก% ( กB C + (+ ก% &I ListView)
ใน Hands On ที่แลว เราอ)านขอมูลทั้งหมดจากฐานขอมูลมาแสดงใน ListView โดยใช
SimpleCursorAdapter สําหรับ Hands On นี้เราจะเพิ่มปุtม 3 ปุtมบนหนาจอ เพื่อใชเพิ่ม แกไข และ

ลบแถวขอมูลในฐานขอมูล ตามลําดับ หลังจากนั้นก็จะตองอัพเดท ListView ดวย


1 แกไข layout โดยเพิ่มปุtม 3 ปุtม

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"

Android: www.3bugs.com
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">

<ListView
android:id="@+id/list_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/insert_button"/>

<Button
android:id="@+id/insert_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:text=" "/>

<Button
android:id="@+id/update_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/insert_button"
android:layout_toEndOf="@+id/insert_button"
android:layout_toRightOf="@+id/insert_button"
android:text=" ก "/>

<Button
android:id="@+id/delete_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/insert_button"
android:layout_toEndOf="@+id/update_button"
android:layout_toRightOf="@+id/update_button"
android:text=" "/>

</RelativeLayout>

Android: www.3bugs.com
2 เพิ่มคําสั่ง implements View.OnClickListener ที่บรรทัดการประกาศคลาส MainActivity
เพื่อใชแอคทิวิตีเป/นตัวจัดการ onClick ของวิว (ใชแอคทิวิตีเป/น onClick listener)
public class MainActivity extends ActionBarActivity
implements View.OnClickListener {

3 เพิ่มโคดทายเมธอด onCreate ของแอคทิวิตี เพื่อกําหนด onClick ของปุtมทั้งสามใหอางอิง


มายังแอคทิวิตีปhจจุบัน (เมื่อปุtมทั้งสามถูกคลิก จะเรียกมายัง onClick ในแอคทิวิตี)
// ก ' " +1))/ +2 onClick listener ก +/3
((Button) findViewById(R.id.insert_button)).setOnClickListener(this);
((Button) findViewById(R.id.update_button)).setOnClickListener(this);
((Button) findViewById(R.id.delete_button)).setOnClickListener(this);

4 เพิ่มเมธอด onClick ภายในแอคทิวิตี


@Override
public void onClick(View v) {
ContentValues cv;
Cursor newCursor;

// ") "( +/3 !ก ก


switch (v.getId()) {
case R.id.insert_button:
cv = new ContentValues();
cv.put(DatabaseHelper.COL_NAME, " ");
cv.put(DatabaseHelper.COL_PHONE_NUMBER, "333-333-3333");
mDb.insert( ❶
DatabaseHelper.TABLE_NAME,
null,
cv
);

newCursor = readAllData(); ❷
mAdapter.changeCursor(newCursor); ❸
break;

Android: www.3bugs.com
case R.id.update_button:
cv = new ContentValues();
cv.put(DatabaseHelper.COL_PHONE_NUMBER, "555-555-5555");
mDb.update( ❶
DatabaseHelper.TABLE_NAME,
cv,
DatabaseHelper.COL_NAME + "=?",
new String[] { " " }
);

newCursor = readAllData(); ❷
mAdapter.changeCursor(newCursor); ❸
break;
case R.id.delete_button:
mDb.delete( ❶
DatabaseHelper.TABLE_NAME,
DatabaseHelper.COL_PHONE_NUMBER + " LIKE ?",
new String[] { "333%" }
);

newCursor = readAllData(); ❷
mAdapter.changeCursor(newCursor); ❸
break;
}
}

จากโคด เราเพิ่ม แกไข และลบขอมูล โดยใชเมธอด insert, update และ delete บนออบเจ็ค
SQLiteDatabase ❶ แต)หากคุณตองการใชเมธอด execSQL ก็สามารถทําไดเช)นกัน

หลังจาก insert, update หรือ delete แลวขอมูลในฐานขอมูลจะเปลี่ยนไป ดังนั้นตองอัพเดท


ขอมูลใน ListView ใหเปลี่ยนตามไปดวย ซึ่งเราเรียกเมธอด readAllData (เป/นเมธอดที่เรา
สรางขึ้นเองในแอคทิวิตี จะอธิบายต)อไป) เพื่อคิวรีฐานขอมูลมาใหม) ❷ แลวนําเคอรเซอรที่ไดมา
กําหนดให adapter เดิมโดยใชเมธอด changeCursor บน adapter ❸ ก็จะทําให ListView
แสดงขอมูลล)าสุดจากฐานขอมูลตามตองการ

Android: www.3bugs.com
ถ้าคุณเคยใช้ ArrayAdapter (adapter ทีน+ ําข้อมูลจากอาร์เรย์มาแสดงผลใน ListView) มา
ก่อน อาจทราบว่า ArrayAdapter มีเมธอด notifyDataSetChanged ซึง+ เมือ+ ข้อมูลในอาร์เรย์
เปลีย+ นไป เราจะเรียกเมธอดนี0เพือ+ อัพเดท ListView
SimpleCursorAdapter ก็มเี มธอด notifyDataSetChanged เช่นเดียวกัน แต่ในตัวอย่างนี0
เราไม่สามารถอัพเดท ListView ด้วยเมธอดดังกล่าวได้ เพราะเมธอดดังกล่าวจะแจ้ง
ListView ว่าแหล่งข้อมูลทีผ + กู อยูก่ บั ListView ซึง+ กรณีน0ีคอื เคอร์เซอร์ เปลีย+ นแปลงไป แต่
สําหรับตัวอย่างนี0 ข้อมูลในเคอร์เซอร์ไม่ได้เปลีย+ น หากแต่เป็ นข้อมูลในฐานข้อมูลทีเ+ ปลีย+ น ดังนัน0
เราจําเป็ นต้องคิวรีฐานข้อมูลใหม่

AdapterView CursorAdapter &( )&C )


& ListView & SimpleCursorAdapter

ฐานข้ อมูล

ความจริงเคอร์เซอร์มเี มธอด requery สําหรับคิวรีฐานข้อมูลใหม่ แต่เอกสารของแอนดรอยด์ระบุ


ว่าให้เลิกใช้เมธอดนี0แล้ว (deprecated) และแนะนําให้ควิ รีใหม่เอง โดยใช้เมธอด เช่น query
หรือ rawQuery ซึง+ จะทําให้ได้เคอร์เซอร์ (result set) อันใหม่ จากนัน0 จึงกําหนดให้ adapter
เปลีย+ นมาใช้ขอ้ มูลจากเคอร์เซอร์ใหม่แทน โดยใช้เมธอด changeCursor บน adapter ดังเช่นใน
ตัวอย่างนี0

5 ที่เมธอด onCreate ในแอคทิวิตี ใหเลือกและตัด (cut) โคดที่ถูกขีดฆ)าต)อไปนี้ แลวเพิ่มบรรทัดที่


มีไฮไลทลงไปแทน ส)วนบรรทัดอื่นๆนอกจากนี้ใหปล)อยไวตามเดิม
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Android: www.3bugs.com
mHelper = new DatabaseHelper(this);
mDb = mHelper.getWritableDatabase();

String[] allColumns = {
DatabaseHelper.COL_ID,
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER
};
Cursor cursor = mDb.query(DatabaseHelper.TABLE_NAME, allColumns, null,
null, null, null, null);

Cursor cursor = readAllData();

...

โคดส)วนที่เราตัดเก็บลงคลิปบอรดนี้ ทําหนาที่อ)านขอมูลทั้งหมดจากฐานขอมูล ซึ่งเราจะยายไป


สรางเป/นเมธอดใหม) เพื่อใหเรียกใชไดจากทั้ง onCreate และ onClick
6 สรางเมธอด readAllData ในแอคทิวิตี แลววางโคดที่ตัดมาจาก onCreate ลงในเมธอดนี้ และ
เพิ่มบรรทัด return cursor; ปeดทาย เพื่อส)งคืนเคอรเซอรที่ไดจากคิวรีกลับออกไป
private Cursor readAllData() {
String[] allColumns = {
DatabaseHelper.COL_ID,
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER
};
Cursor cursor = mDb.query(DatabaseHelper.TABLE_NAME, allColumns, null,
null, null, null, null);
return cursor;
}

Android: www.3bugs.com
โค้ ดทั.งหมดในแอคทิวติ ี
ตอนนี้แอคทิวิตีจะมีโคดทั้งหมดดังนี้
package com.example.sqlitebasics;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

public class MainActivity extends AppCompatActivity


implements View.OnClickListener {

private DatabaseHelper mHelper;


private SQLiteDatabase mDb;
private SimpleCursorAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mHelper = new DatabaseHelper(this);


mDb = mHelper.getWritableDatabase();

Cursor cursor = readAllData();


// result set ).' ก
String[] showColumns = {
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER
};

Android: www.3bugs.com
// "" layout ).) (ก result set
int[] views = {
android.R.id.text1,
android.R.id.text2
};

// adapter
mAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2, cursor, showColumns, views, 0);
// ก adapter ก ListView
((ListView) findViewById(R.id.listView)).setAdapter(mAdapter);

// ก ' " +1))/ +2 onClick listener ก +/3


((Button) findViewById(R.id.insert_button)).setOnClickListener(this);
((Button) findViewById(R.id.update_button)).setOnClickListener(this);
((Button) findViewById(R.id.delete_button)).setOnClickListener(this);
}

private Cursor readAllData() {


String[] allColumns = {
DatabaseHelper.COL_ID,
DatabaseHelper.COL_NAME,
DatabaseHelper.COL_PHONE_NUMBER
};
Cursor cursor = mDb.query(DatabaseHelper.TABLE_NAME, allColumns, null,
null, null, null, null);
return cursor;
}

@Override
protected void onDestroy() {
super.onDestroy();

// +, *
mAdapter.getCursor().close();
mHelper.close();
}

Android: www.3bugs.com
@Override
public void onClick(View v) {
ContentValues cv;
Cursor newCursor;

// ") "( +/3 !ก ก


switch (v.getId()) {
case R.id.insert_button:
cv = new ContentValues();
cv.put(DatabaseHelper.COL_NAME, " ");
cv.put(DatabaseHelper.COL_PHONE_NUMBER, "333-333-3333");
mDb.insert(
DatabaseHelper.TABLE_NAME,
null,
cv
);

newCursor = readAllData();
mAdapter.changeCursor(newCursor);
break;
case R.id.update_button:
cv = new ContentValues();
cv.put(DatabaseHelper.COL_PHONE_NUMBER, "555-555-5555");
mDb.update(
DatabaseHelper.TABLE_NAME,
cv,
DatabaseHelper.COL_NAME + "=?",
new String[] { " " }
);

newCursor = readAllData();
mAdapter.changeCursor(newCursor);
break;
case R.id.delete_button:
mDb.delete(
DatabaseHelper.TABLE_NAME,
DatabaseHelper.COL_PHONE_NUMBER + " LIKE ?",
new String[] { "333%" }
);

Android: www.3bugs.com
newCursor = readAllData();
mAdapter.changeCursor(newCursor);
break;
}
}
}

ทดสอบการเพิมข้ อมูล

(#ก (d '? E(#ก 2 ( E )

Android: www.3bugs.com
ทดสอบการแก้ ไขข้ อมูล

(#ก

Android: www.3bugs.com
ทดสอบการลบข้ อมูล

(#ก

Android: www.3bugs.com

You might also like