ก่อนอื่นเลย คงจะรู้อยู่แล้วว่าบนแอนดรอยด์มี SQLite ให้ใช้ โดยที่ปกติมักจะสร้างฐานข้อมูลตอนที่เปิดแอพพลิเคชันเป็นครั้งแรกและในครั้งต่อไปก็ไม่ต้องสร้างแล้ว เปิดจากฐานข้อมูลมาใช้ต่อเลย
ถ้าข้อมูลมีนิดหน่อยก็คงไม่เจอปัญหาอะไรซักเท่าไร (พันกว่าตัว) แต่ถ้าข้อมูลมีขนาดเยอะมาก การสร้างฐานข้อมูลจะใช้เวลานานมาก อย่างเช่นแอพคำศัพท์สำหรับ Dictionary ของ Lexitron ที่มีคำศัพท์ประมาณ 8 หมื่นคำ มีคอลัมน์ 8 คอลัมน์ ข้อมูลโดยรวมแล้วตกประมาณ 10MB กว่าๆเลยทีเดียว พวกนี้จะใช้เวลาเป็นสิบนาทีเลยทีเดียว
ทีนี้ลองนึกถึงผู้ใช้ที่โหลดแอพไปใช้ แล้วพบว่าเปิดแอพครั้งแรกต้องมานั่งรอสร้างฐานข้อมูลสิบกว่านาที ใครจะไปนั่งรอใช้กันล่ะ? ถ้าเป็นแอพเกมสนุกๆก็ว่าไปอย่าง ดังนั้นเจ้าของบล็อกจึงเขียนบทความนี้ขึ้นมาเพื่อพูดถึง "วิธีลัด" ในการสร้างฐานข้อมูลขนาดใหญ่ ให้ใช้เวลาน้อย
สำหรับไฟล์ฐานข้อมูลจะสร้างจากไหนก็ได้ขอแค่ว่าเป็น SQLite หรือจะสร้างจาก SQLite Databases Browser ก้ได้
เมื่อได้ไฟล์ฐานข้อมูลมาแล้วก็เอาไปไว้ในโปรเจคได้เลย โดยเอาไว้ใน assets จะดีกว่าเพราะว่าสามารถเรียก Path ได้เลย
เมื่อได้ไฟล์ฐานข้อมูลมาพร้อมแล้ว เวลาเขียนโปรแกรมก็ทำการเช็คก่อน ว่ามีไฟล์ฐานข้อมูลแล้วหรือยัง โดยเช็คว่ามีไฟล์ใน data/data/package_name/databases/database_file หรือไม่ ถ้ายังไม่มีก็ให้ก๊อปไฟล์ฐานข้อมูลที่เตรียมไว้ไปวางแทน แต่ถ้ามีแล้วก็ข้ามไปให้แอพทำงานต่อตามต้องการเลย
สรุปก็คือจะใช้วิธีสร้างไฟล์ฐานข้อมูลเตรียมเอาไว้เลยแล้วจะใช้คำสั่งโยนไฟล์ดังกล่าวไปไว้ในตำแหน่งที่ไฟล์ฐานข้อมูลอยู่ ทีนี้ก็ลองดูตัวอย่างเลยดีกว่า
Main.java
package app.akexorcist.databasequicksqlite;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import android.os.Bundle;
import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
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);
checkDatabase();
ListView listView1 = (ListView)findViewById(R.id.listView1);
ArrayList<String> dirArray = new ArrayList<String>();
mHelper = new MyDbHelper(this);
mDb = mHelper.getWritableDatabase();
mCursor = mDb.rawQuery("SELECT * FROM " + MyDbHelper.TABLE_NAME, null);
mCursor.moveToFirst();
while(!mCursor.isAfterLast()){
dirArray.add("Name : "
+ mCursor.getString(mCursor.getColumnIndex(MyDbHelper.COL_NAME))
+ "\nPiece Price : "
+ mCursor.getString(mCursor.getColumnIndex(MyDbHelper.COL_PIECE_PRICE))
+ "\nCake Price"
+ mCursor.getString(mCursor.getColumnIndex(MyDbHelper.COL_CAKE_PRICE)));
mCursor.moveToNext();
}
ArrayAdapter<String> adapterDir = new ArrayAdapter<String>(getApplicationContext()
, android.R.layout.simple_list_item_1, dirArray);
listView1.setAdapter(adapterDir);
}
public void checkDatabase() {
String url = "/data/data/" + getPackageName() + "/databases/BTS";
File f = new File(url);
if(!f.exists()) {
try {
mHelper = new MyDbHelper(this);
mDb = mHelper.getWritableDatabase();
mDb.close();
mHelper.close();
InputStream in = getAssets().open("BTS");
OutputStream out = new FileOutputStream(url);
byte[] buffer = new byte[in.available()];
in.read(buffer);
out.write(buffer, 0, buffer.length);
in.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void onPause() {
super.onPause();
mHelper.close();
mDb.close();
}
}
สำหรับคำสั่งใน Main.java ก็จะเหมือนกับคำสั่งสร้างฐานข้อมูลทั่วๆไปที่เอาข้อมูลในฐานข้อมูลมาแสดงบน List View แต่ว่าเจ้าของบล็อกจะมีการสร้างฟังก์ชัน checkDatabase ขึ้นมา ซึ่งเป็นฟังก์ชันตรวจสอบว่าไฟล์ฐานข้อมูลถูกสร้างขึ้นหรือยัง ทีนี้ขอข้ามไปอธิบายฟังก์ชัน checkDatabase เลยนะ สำหรับฟังก์ชันนี้ ก็จะสร้าง String ขึ้นมาเพื่อเก็บที่อยู่ของไฟล์ จะเห็นว่าเจ้าของบล็อกใช้ "/data/data/" + getPackageName() + "/databases/BTS" โดยที่ getPackageName() คือคำสั่งรับชื่อ Package ของแอพนั้นๆให้ทันที เวลาผู้ที่หลงเข้ามาอ่านเอาไปใช้ก็ไม่ต้องแก้ชื่อ Package เลย จากนั้นก็เรียกใช้คลาส File ขึ้นมา โดยใช้ URL จากตัวแปร String เมื่อกี้
ซึ่งก็คือ Object ตัวนี้จะ Path ไปยังไฟล์ที่กำหนดเป็น URL แล้วทำการเช็คด้วย if ว่ามีไฟล์ดังกล่าวอยู่หรือไม่ด้วยคำสั่ง f.exists() โดยใช้ ! ด้วย เพราะว่าจะให้ทำเงื่อนไขเมื่อไม่มีไฟล์นี้อยู่ เมื่อเข้าเงื่อนไขว่ายังไม่มีไฟล์ฐานข้อมูลอยู่ในเครื่องก็ให้เรียกใช้คลาสฐานข้อมูลเพื่อสร้างฐานข้อมูลเปล่าๆก่อน แล้วก็ปิดฐานข้อมูลซะ ไม่งั้นจะวางไฟล์ทับไม่ได้เพราะเปิดใช้งานอยู่ จากนั้นก็เรียกใช้คลาสของ InputStream กับ OutputStream เพื่อใช้สำหรับนำไฟล์ฐานข้อมูลที่เตรียมไว้ไปวางทับฐานข้อมูลเปล่า เท่านี้ก็เสร็จเรียบร้อยแล้ว
MyDbHelper.java
package app.akexorcist.databasequicksqlite;
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) { }
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
สำหรับคลาสนี้ก็ไม่มีอะไร แค่คลาส Database ปกติ โดยรวมของคลาสนี้ก็มีแค่สร้างฐานข้อมูลเปล่าๆ ที่ไม่มีตารางและฐานข้อมูลใดๆเลย เพราะจะนำไฟล์ฐานข้อมูลมาวางทับ
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>
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.akexorcist.databasequicksqlite"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".Main"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
เรียบร้อยแล้ว ลองเอาไปทดสอบดูก็จะพบว่าไวกว่าเดิมเยอะ
สำหรับผู้ที่หลงเข้ามาอ่านคนใดต้องการดาวน์โหลดไฟล์ตัวอย่างสามารถดาวน์โหลดได้จากที่นี่เลย Database Quick SQLite [Google Drive]
ลองเอาวิธีนี้ไปใช้ดูละกันนะ