Tuesday, May 25, 2010

Làm việc với Database trên Android (P2)

Lần trước mình đã đề cập đến việc tạo một lớp quản lý chung với một số tác vụ:
- Tạo database
- Chạy câu SQL
- Tạo table
- ....
Lần này mình xin giới thiệu để tạo một thể hiện của một trường trong Database SQLite
Trong SQLite chỉ có 3 kiểu dữ liệu là: INT, TEXT, BOOL
Vì thế ta cần tạo một biến enum chứa một bộ các hằng số về kiểu dữ liệu này. Sau đó implement một số phương thức như trong VD sau


package com.tannm.doan.taskmanager.database;

import java.util.Calendar;
import android.content.*;

public class DataField {
// types
public static enum Type {
INT, TEXT, BOOL
};

// fields
private Calendar dateOut = Calendar.getInstance();

// fields
private DataRow dataRow = null;
private ContentValues values = null;

// fields
private int index = 0;
private String sName = "";
private Type fieldType = Type.INT;
private boolean bCanBeNull = true;
private boolean bPrimaryKey = false;

// methods
public DataField(int index, String sName, Type fieldType,
boolean bCanBeNull, boolean bPrimaryKey) {
this.index = index;
this.sName = sName;
this.fieldType = fieldType;
this.bCanBeNull = bCanBeNull;
this.bPrimaryKey = bPrimaryKey;
}

public String getColumnDefinition() {
String s = sName + " " + getSqlType(fieldType);
if (bPrimaryKey)
s += " PRIMARY KEY";
if (!bCanBeNull)
s += " NOT NULL";
return s;
}

public Type getType() {
return fieldType;
}

public int getIndex() {
return index;
}

public String getSqlType(Type value) {
switch (value) {
case INT:
return "INTEGER";
case TEXT:
return "TEXT";
case BOOL:
return "INTEGER";
}
return "TEXT";
}

public void setParentRow(DataRow dataRow) {
this.dataRow = dataRow;
this.values = this.dataRow.getContentValues();
}

public String getName() {
return sName;
}

// getters
public String asString() {
return values.getAsString(sName);
}

public long asLong() {
return values.getAsLong(sName);
}

public boolean asBoolean() {
return (values.getAsLong(sName) == 1);
}

public boolean isNull() {
return (values.get(sName) == null);
}

public Calendar asCalendar() {
dateOut.setTimeInMillis(values.getAsLong(sName));
return dateOut;
}

// setters
public void set(String value) {
values.put(sName, value);
}

public void set(long value) {
values.put(sName, value);
}

public void set(boolean value) {
int i = (value) ? 1 : 0;
values.put(sName, i);
}

public void set(Calendar value) {
values.put(sName, value.getTimeInMillis());
}

public void setNull() {
values.put(sName, (String) null);
}
}

Monday, May 24, 2010

Làm việc với Database trên Android (P1)

Cách lưu trữ dữ liệu trên Android bao gồm 3 cách:
+ Sử dụng Shared Preferences
+ Sử dụng file
+ Sử dụng SQLite
Với Shared Preferences (Là lưu dữ liệu dưới dạng một cặp khóa - dữ liệu dưới dạng file xml, rất tiện cho việc lưu trữ cấu hình của ứng dụng) và lưu dữ liệu dưới dạng File thì đơn giản nên mình không đề cập ở đây.
Kiến thức về SQLite mình cũng không nhắc đến nữa, vì mình đã có bài nói về vấn đề này trước đây rồi.
Kinh nghiệm của mình để làm việc với SQLite là:
+ Tạo một lớp quản lý chung với một số tác vụ:
-Tạo database
-Chạy câu SQL
-Tạo table
....
+ Tạo một lớp thể hiện một trường trong database bởi SQLite chỉ hỗ trợ 3 loại dữ liệu nên việc này cũng rất đơn giản.
+ Tạo một lớp thể hiện cho một dòng (row) dữ liệu
+ Tạo một lớp cho thể hiện một table.
Sau đây chúng ta sẽ đi lần lượt từng công việc trên


Đầu tiên ta sẽ đi từ việc tạo một lớp quản lý chung việc tạo database cụ thể bạn có thể xem VD để hiểu việc này
package com.tannm.doan.taskmanager.database;

import java.util.Vector;
import com.tannm.doan.taskmanager.R;
import android.content.*;
import android.database.sqlite.*;
import android.database.*;

public class Database {
// types
public enum Result {
Success, errUnknown, errCantInsertNewData, errCantUpdateData, errCantCreateTable, errNoDbAccess, errCantGetDataFromTable, errCantFindData, errCantGetData, errCantDeleteData, errTableNotExists, errCantSetValuesForDataRow, errCantGetValuesFromDataRow,
};

// fields
public static final String sTableNameAppointments = "Appointments";
public static final String sTableNameTasks = "Tasks";
public static final String sTableNameNotes = "Notes";
public static final String sTableNameAlarms = "Alarms";
public static final String sTableNameEvent = "Event";

// fields
private final String dbName = "TaskManagerDatabase.db";
private Context ctx = null;
private SQLiteDatabase db = null;
private Result resultDbTablesCreated = Result.errUnknown;

// methods
public Database(Context context) {
ctx = context;
open();
createTables();
}

public final String getName() {
return dbName;
}

public static int getErrDesc(Result result) {
int msgId = R.string.errUnknown;
if (result == Result.errCantInsertNewData)
msgId = R.string.errCantInsertNewData;
if (result == Result.errCantUpdateData)
msgId = R.string.errCantUpdateData;
if (result == Result.errCantCreateTable)
msgId = R.string.errCantCreateTable;
if (result == Result.errNoDbAccess)
msgId = R.string.errNoDbAccess;
if (result == Result.errCantGetDataFromTable)
msgId = R.string.errCantGetDataFromTable;
if (result == Result.errCantFindData)
msgId = R.string.errCantFindData;
if (result == Result.errCantGetData)
msgId = R.string.errCantGetData;
if (result == Result.errCantDeleteData)
msgId = R.string.errCantDeleteData;
if (result == Result.errTableNotExists)
msgId = R.string.errTableNotExists;
if (result == Result.errCantSetValuesForDataRow)
msgId = R.string.errCantSetValuesForDataRow;
if (result == Result.errCantGetValuesFromDataRow)
msgId = R.string.errCantGetValuesFromDataRow;
return msgId;
}

public boolean open() {
boolean bSuccess = false;
// open / create database
db = ctx.openOrCreateDatabase(dbName, Context.MODE_PRIVATE, null);
// test result
if (isOpened()) {
bSuccess = true;
} else {
db = null;
}
return bSuccess;
}

public void close() {
if (isOpened())
db.close();
}

public boolean isOpened() {
if (db != null)
return true;
return false;
}

public SQLiteDatabase getSQLiteDb() {
return db;
}

public boolean delete() {
close();
return ctx.deleteDatabase(dbName);
}

public boolean execSQL(String sql) {
boolean bSuccess = false;
try {
if (isOpened())
db.execSQL(sql);
bSuccess = true;
} catch (SQLException e) {
}
return bSuccess;
}

public boolean tableExists(String sTableName) {
boolean bResult = false;
if (isOpened()) {
String sql = "select name from sqlite_master where type = 'table' and name = '%s'";
sql = String.format(sql, sTableName);
Cursor cr = db.rawQuery(sql, null);
if (cr.getCount() > 0)
bResult = true;
cr.close();
}
return bResult;
}

private void createTables() {
resultDbTablesCreated = Database.Result.errUnknown;
if (isOpened()) {
Vector vecDataRows = new Vector();
vecDataRows.add(new DataRowAppointment(this));
vecDataRows.add(new DataRowTask(this));
vecDataRows.add(new DataRowNote(this));
vecDataRows.add(new DataRowAlarm(this));

for (int i = 0; i < vecDataRows.size(); i++) {
DataTable dataTable = new DataTable(vecDataRows.get(i));
if (dataTable.createTable()) {
resultDbTablesCreated = Database.Result.Success;
} else {
resultDbTablesCreated = Database.Result.errCantCreateTable;
break;
}
}
} else {
resultDbTablesCreated = Database.Result.errNoDbAccess;
}
}

public boolean tablesCreated() {
return resultDbTablesCreated == Result.Success;
}

public synchronized boolean databaseReady() {
return (isOpened() && tablesCreated());
}

public Result tablesCreationResult() {
return resultDbTablesCreated;
}
}


Hãy đọc và suy ngẫm về ứng dụng cho các ví dụ tiếp theo.
(Còn tiếp)