26 มิถุนายน 2555

[Android Code] SQLite บน Android เบื้องต้น (แอบละเอียด)


        บทความคราวนี้จะเป็นเรื่องของฐานข้อมูลกันบ้าง ก็เจ้าของบล็อกไม่อธิบายเรื่องฐานข้อมูลอีกนั่นแหละ ขออธิบายเนื้อหาหลักๆพอ (ขี้เกียจน่ะแหละ...)

        สำหรับการใช้ฐานข้อมูลบนแอนดรอยด์ โดยจะใช้เป็น SQLite กัน ได้อารมณ์ SQL เลยนี่แหละ เริ่มจากการสร้างฐานข้อมูลแล้วแสดงใน ListView ละกัน

        ก่อนอื่นก็ให้ลองสร้างโปรเจคขึ้นมาอันนึงก่อน เจ้าของบล็อกตั้งชื่อว่า Database Basic


        ทีนี้ก็ให้สร้าง Class ขึ้นมาสำหรับ Database โดยเจ้าของบล็อกจะตั้งชื่อเป็น Database.java จริงๆจะสร้างใน Main.java ก็ได้ แต่ในกรณีที่โปรแกรมมีความซับซ้อนมาก สร้างไฟล์แบบนี้จะช่วยให้จัดการสะดวกกว่า




        ทีนี้ก็มาจัดการกับเจ้าไฟล์ Database.java ก่อนละกัน โดยคลาสของฐานข้อมูลจะอยู่ในนี้ทั้งหมด เจ้าของบล็อกจะตั้งชื่อคลาสว่า MyDbHelper ถ้าจะเอาไปใช้ก็แก้ให้ตรงกับของผู้ที่หลงเข้ามาอ่านด้วยนะ

Database.java
package app.akexorcist.databasesample;
  
import android.content.Context;  
import android.database.sqlite.SQLiteDatabase;  
import android.database.sqlite.SQLiteOpenHelper;  

class MyDbHelper extends SQLiteOpenHelper {  
    private static final String DB_NAME = "BTS";  
    private static final int DB_VERSION = 1;  
    public static final String TABLE_NAME = "Product";  
    public static final String COL_NAME = "name";  
    public static final String COL_PIECE_PRICE = "pieceprice";  
    public static final String COL_CAKE_PRICE = "cakeprice";  

    public MyDbHelper(Context context) {  
        super(context, DB_NAME, null, DB_VERSION);  
    }  

    public void onCreate(SQLiteDatabase db) {  
        db.execSQL("CREATE TABLE " + TABLE_NAME +" (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
                + COL_NAME + " TEXT, " + COL_PIECE_PRICE + " INTEGER, " 
                + COL_CAKE_PRICE + " INTEGER);");  
        db.execSQL("INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_PIECE_PRICE 
                + ", " + COL_CAKE_PRICE + ") VALUES ('Chocolate Fudge', 95, 750);");   
        db.execSQL("INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_PIECE_PRICE 
                + ", " + COL_CAKE_PRICE + ") VALUES ('Banana Choc Cake', 55, 500);");   
        db.execSQL("INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_PIECE_PRICE 
                + ", " + COL_CAKE_PRICE + ") VALUES ('Banoffee', 75, 700);");   
        db.execSQL("INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_PIECE_PRICE 
                + ", " + COL_CAKE_PRICE + ") VALUES ('Cheese Cake', 85, 800);");   
        db.execSQL("INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_PIECE_PRICE 
                + ", " + COL_CAKE_PRICE + ") VALUES ('Tiramisu', 85, 800);");   
    }  

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);  
        onCreate(db);  
    }  
}  

public class Database { } 

        เจ้าของบล็อกแนะนำให้สร้างตัวแปร String เอาไว้เก็บชื่อต่างๆไว้ เพราะเวลาแก้ไขจะสะดวกกว่า โดยแต่ละอันก็จะมีความหมายดังนี้

                DB_NAME คือชื่อฐานข้อมูลของเรา
                DB_VERSION คือเวอร์ชันของฐานข้อมูลเอาไว้ใช้เวลาอัพเกรดฐานข้อมูล
                TABLE_NAME ชื่อตาราง

        สำหรับ COL_NAME, COL_PIECE_PRICE และ COL_CAKE_PRICE ก็ขึ้นอยู่กับว่า ผู้ที่หลงเข้ามาอ่านจะให้แต่ละคอลัมน์เป็นอะไรก็พยายามตั้งให้จำได้ง่ายก็แล้วกัน

        ในส่วนฟังก์ชัน onCreate ของฐานข้อมูลก็เปรียบเสมือน onCreate ของ Activity จะเริ่มทำงานทันทีที่มีการเรียกใช้คลาสนี้ แต่จะสร้างครั้งแรกที่ยังไม่มีฐานข้อมูลเท่านั้น ถ้าแก้ไขฐานข้อมูลใหม่ ก็จะไม่มีการเรียกซ้ำอีกครั้ง ต้องใช้ onUpgrade แทน หรือจะลบแอพฯแล้วลงใหม่ก็ได้

        ในฟังก์ชัน onCreate จะเห็นว่ามีคำสั่ง db.execSQL ที่มีคำสั่งสร้างตารางและเพิ่มข้อมูลลงในตารางนั่นเอง ก็จะเป็นคำสั่ง SQL ทั้งหมดเลย

        สุดท้ายคือฟังก์ชัน onUpgrade ที่ทำงานเมื่อจะอัพเกรดฐานข้อมูล โดยจะให้ลบของเก่าทิ้งแล้วสร้างขึ้นมาใหม่นั่นเอง


        ต่อมาก็เป็นส่วนของ Main.java ล่ะ แต่ก่อนอื่นไปสร้าง Layout ก่อนดีกว่า โดย main.xml ของเจ้าของบล็อกจะใช้ตามนี้

main.xml
<?xml version="1.0" encoding="utf-8"?>  
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    android:orientation="vertical"  
    android:background="#666666" >  
    <TextView  
        android:id="@+id/textView1"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="Cake Menu"  
        android:textColor="#222222"  
        android:textSize="40dp"  
        android:gravity="center"  
        android:layout_marginTop="20dp" />  
    <ListView  
        android:id="@+id/listView1"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_margin="30dp"  
        android:cacheColorHint="#00000000" />  
 </LinearLayout>  

        ก็จะได้ Layout หน้าตาง่ายๆแบบนี้


        ทีนี้ถึงตา Main.java กันบ้าง

Main.java
package app.akexorcist.databasesample;  

import java.util.ArrayList;  
import android.app.Activity;  
import android.database.Cursor;  
import android.database.sqlite.SQLiteDatabase;  
import android.os.Bundle;  
import android.view.Window;  
import android.widget.ArrayAdapter;  
import android.widget.ListView;  

public class Main extends Activity {  
    SQLiteDatabase mDb;  
    MyDbHelper mHelper;  
    Cursor mCursor;  

    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        requestWindowFeature(Window.FEATURE_NO_TITLE);  
        setContentView(R.layout.main);  

        ListView listView1 = (ListView)findViewById(R.id.listView1);

        mHelper = new MyDbHelper(this);  
        mDb = mHelper.getWritableDatabase();  
        mCursor = mDb.rawQuery("SELECT " + MyDbHelper.COL_NAME + ", "  + MyDbHelper.COL_PIECE_PRICE 
                + ", " + MyDbHelper.COL_CAKE_PRICE + " FROM " + MyDbHelper.TABLE_NAME, null);  
        
        ArrayList<String> dirArray = new ArrayList<String>();  
        mCursor.moveToFirst();  

        while ( !mCursor.isAfterLast() ){  
            dirArray.add(mCursor.getString(mCursor.getColumnIndex(MyDbHelper.COL_NAME)) + "\n"
                    + "Piece : " + mCursor.getString(mCursor.getColumnIndex(MyDbHelper.COL_PIECE_PRICE)) + "\t\t"
                    + "Cake : " + mCursor.getString(mCursor.getColumnIndex(MyDbHelper.COL_CAKE_PRICE)));  
            mCursor.moveToNext();    
        }  

        ArrayAdapter<String> adapterDir = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, dirArray);  
        listView1.setAdapter(adapterDir);  
    }  

    public void onPause() {  
        super.onPause();  
        mHelper.close();  
        mDb.close();   
    }  
 }  

        อาจจะดูวุ่นวายเล็กน้อย แต่ก็เป็นส่วนที่เป็น String นั่นแหละ จะเห็นว่าจะมีการเรียกใช้คลาสสำหรับฐานข้อมูลอยู่ 3 ตัว

        SQLiteDatabase จะเป็นเมธอดสำหรับจัดการฐานข้อมูลพวกคำสั่งที่ใช้ในฐานข้อมูล
        Cursor คลาสที่เป็นเคอร์เซอร์ว่าเลือกข้อมูลแถวที่เท่าไรและดึงข้อมูลๆผ่านตัวนี้
        MyDbHelper คลาสฐานข้อมูลที่สร้างไว้ใน Database.java

        สำหรับใน onCreate ก็จะขออธิบายแต่ละบรรทัดเลยละกัน เมื่อเข้ามาในฟังก์ชัน onCreate ก็จะเห็นว่ามีคำสั่ง
requestWindowFeature(Window.FEATURE_NO_TITLE);
        อันนี้เจ้าของบล็อกเอาไว้กำหนดไม่ต้องแสดง Title ของแอพฯ ถ้างงก็ดูรูปข้างล่าง ตรงคำว่า Database Sample นั่นแหละ


        แล้วก็ทำการสร้าง listView1 ขึ้นมา เพื่อใช้แสดงข้อมูลจากฐานข้อมูล
ListView listView1 = (ListView)findViewById(R.id.listView1);

        ทีนี้ก็จะเป็นการเรียกใช้ฐานข้อมูลแล้ว โดยสร้างคลาส MyDbHelper
mHelper = new MyDbHelper(this);

        ต่อมาก็เริ่มทำการเปิดฐานข้อมูลขึ้นมาด้วย mDb ที่ประกาศไว้
mDb = mHelper.getWritableDatabase();

        ฐานข้อมูลจะถูกสร้างพร้อมกับข้อมูลที่กำหนดใน Database.java ในกรณีที่มีฐานข้อมูลอยู่แล้วก็จะทำการเปิดฐานข้อมูลเท่านั้น

        ต่อมาจะเป็นการดึงข้อมูลจากฐานข้อมูลล่ะ โดยใช้ mCursor
mCursor = mDb.rawQuery("SELECT " + MyDbHelper.COL_NAME + ", " + MyDbHelper.COL_PIECE_PRICE + ", " 
        + MyDbHelper.COL_CAKE_PRICE + " FROM " + MyDbHelper.TABLE_NAME, null);
        สำหรับคำสั่ง rawQuery จะทำให้ใช้คำสั่ง SQL ได้เลย โดยเจ้าของบล็อกจะดึง String ที่สร้างไว้ใน Database.java มาใช้เลยทำให้ดูงง (แต่จริงๆก็ควรทำแบบนี้แหละ) จริงๆแล้วก็จะเป็นแบบนี้
"SELECT name, pieceprice, cakeprice FROM Product"
        สามารถใช้ WHERE, DESC หรือคำสั่งอื่นๆของ SQL ได้ด้วยนะ

        ต่อมาก็สร้างArrayList แบบ String เพื่อเก็บข้อมูลจากฐานข้อมูล
ArrayList<String> dirArray = new ArrayList<String>();

        ก่อนอื่นเลยให้เลื่อนเคอร์เซอร์มายังข้อมูลแถวแรกสุดก่อน
mCursor.moveToFirst();

        แล้วให้วนลูปด้วย While และในการวนลูปแต่ละครั้งจะให้เคอร์เซอร์เลื่อนบรรทัดไปด้วย
mCursor.moveToNext();
        และมีเงื่อนไขของ While ว่า !mCursor.isAfterLast() ซึ่งก็คือวนลูปจนกว่าเคอร์เซอร์จะถึงบรรทัดก่อนสุดท้าย เพราะว่าพอทำงานถึงบรรทัดก่อนสุดท้ายแล้วก็จะทำงานอีกรอบนึงจึงเป็นบรรทัดสุดท้ายพอดี

        โดยในการวนแต่ละรอบก็จะมีการเก็บข้อมูลไว้ใน dirArray โดยใช้คำสั่ง dirArray.Add(String) เวลาดึงข้อมูลจากตาราง จะเลือกได้ว่าจะเป็นข้อมูลแบบใด มี getString, getInt, getDouble, getLong และ getFloat แต่ ArrayList ของเจ้าของบล็อกเป็น String เพราะจะเอาไปแสดงใน ListView เท่านั้น ไม่ได้ใช้คำนวณ ก็เลยใช้ getString แทน ซึ่งในคำสั่ง getString ก็จะให้กำหนด ColumnIndex ว่าจะเอาข้อมูลในคอลัมน์เท่าไรของแถวนั้น ซึ่งเจ้าของบล็อกก็จะใช้คำสั่ง getColumnIndex(string) อีกทีหนึ่ง เพื่อระบุเป็น String แทน ซึ่งเจ้าของบล้อกก็ใส่เป็น MyDbHelper.COL_NAME ก็จะเป็นคอลัมน์ที่ชื่อว่า name คำสั่งนี้ก็จะส่งค่าออกมาเป็นเลขคอลัมน์ให้ ทีนี้ก็จะได้ข้อมูลของแถวและคอลัมน์นั้นๆแล้ว และจะเห็นเนื่องจากคำสั่ง dirArray.Add(String) รับค่า String ก็เลยเก็บค่า pieceprice กับcakeprice ด้วยเลย โดยใช้ \n ขึ้นบรรทัดใหม่ และ \t\t เพื่อเขยิบไป 2 Tab

        ต่อมาก็สร้าง ArrayAdapter เพื่อแสดงข้อมูลใน dirArray บน ListView
ArrayAdapter<String> adapterDir = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, dirArray);

        เมื่อเตรียมทั้งหมดเรียบร้อยแล้วก็แสดงใน ListView ได้เลย
listView1.setAdapter(adapterDir);

        และควรมีการปิดฐานข้อมูลด้วย เมื่อแอพฯหยุดทำงาน โดยจะให้ปิดตอนที่ onPause หรือจะใช้ทันทีหลังจากดึงข้อมูลแล้วก็ได้
mHelper.close();
mDb.close();


        เพียงเท่านี้ก็แสดงฐานข้อมูลขึ้นบน List View ได้แล้ว



        เพิ่มเติม - สำหรับการอัพเกรดฐานข้อมูลใหม่ จากแอพตัวอย่างนี้ให้ลองใช้คำสั่ง
mHelper.onUpgrade(mDb, 1, 1);
        โดยใส่ต่อท้ายคำสั่ง
mHelper = new MyDbHelper(this);
mDb = mHelper.getWritableDatabase();
        เพื่อให้ mHelper และ mDb ถูกสร้างขึ้นมาก่อน

        สำหรับผู้ที่หลงเข้ามาอ่านที่อยากจะเอาไฟล์ตัวอย่างไปลอง ก็ดาวน์โหลดจากตรงนี้ได้เลย Database Sample [Google Drive]


        พิมซะยาวเลย 5555+




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium