Showing posts with label SQLite. Show all posts
Showing posts with label SQLite. Show all posts

Wednesday, June 9, 2010

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

Ngoài ra ta cần có một lớp khai báo một số các phương thức utility để dễ dàng làm việc với Database. Bạn hãy xem ví dụ để thấy cụ thể các phương thức này.

package com.tannm.doan.taskmanager.database;

import android.database.Cursor;

public class DataTable {
 // fields
 private DataRow dataRow = null;

 // methods
 public DataTable(DataRow dataRow) {
  this.dataRow = dataRow;
 }

 public Database getUserDb() {
  return dataRow.getUserDb();
 }

 public String getTableName() {
  return dataRow.getTableName();
 }

 public DataRow getDataRow() {
  return dataRow;
 }

 public boolean createTable() {
  if (getUserDb().tableExists(getTableName())) {
   return true;
  } else {
   return getUserDb()
     .execSQL(
       getSqlTableDefinition(getTableName(), dataRow
         .getTableDef()));
  }
 }

 public String getSqlTableDefinition(String sTableName,
   DataField[] vecTableDef) {
  String def = "CREATE TABLE " + sTableName + " (";
  for (int i = 0; i < vecTableDef.length; i++) {
   def += vecTableDef[i].getColumnDefinition();
   if (i < (vecTableDef.length - 1))
    def += ", ";
  }
  def += ")";
  return def;
 }

 public long insertValues() {
  long lRowId = getUserDb().getSQLiteDb().insert(getTableName(), null,
    dataRow.getContentValues());
  return lRowId;
 }

 public long updateValues(long lRowId) {
  String sWhere = String.format("_ID = %d", lRowId);
  long lRowsUpdated = getUserDb().getSQLiteDb().update(getTableName(),
    dataRow.getContentValues(), sWhere, null);
  return lRowsUpdated;
 }

 public long deleteDataRow(long lRowId) {
  String sWhere = String.format("_ID = %d", lRowId);
  long lRowsUpdated = getUserDb().getSQLiteDb().delete(getTableName(),
    sWhere, null);
  return lRowsUpdated;
 }

 public Cursor locateDataRow(long lRowId) {
  final String s = "select * from %s where _ID = %d";
  String sql = String.format(s, getTableName(), lRowId);
  Cursor cr = getUserDb().getSQLiteDb().rawQuery(sql, null);
  // if cursor valid, set first data row as current
  if ((cr != null) && (cr.getCount() > 0))
   cr.moveToFirst();
  return cr;
 }

 public Cursor locateAlarmDataRow(int iType, long lRefID) {
  final String s = "select * from %s where Type = %d and RefID = %d";
  String sql = String.format(s, getTableName(), iType, lRefID);
  Cursor cr = getUserDb().getSQLiteDb().rawQuery(sql, null);
  // if cursor valid, set first data row as current
  if ((cr != null) && (cr.getCount() > 0))
   cr.moveToFirst();
  return cr;
 }

 public Database.Result updateData(boolean bInsertMode, long lEditRowId) {
  Database.Result result = Database.Result.errUnknown;
  if (getUserDb().isOpened()) {
   try {
    dataRow.setValuesForDataRow();
   } catch (Exception e) {
    return Database.Result.errCantSetValuesForDataRow;
   }
   // select update mode
   if (bInsertMode) {
    // insert new data row
    long lRowId = insertValues();
    if (lRowId > 0) {
     result = Database.Result.Success;
    } else {
     result = Database.Result.errCantInsertNewData;
    }
   } else {
    // update existing data row
    long lRowsUpdated = updateValues(lEditRowId);
    if (lRowsUpdated == 1) {
     result = Database.Result.Success;
    } else {
     result = Database.Result.errCantUpdateData;
    }
   }
  } else {
   result = Database.Result.errNoDbAccess;
  }
  return result;
 }

 public Database.Result deleteData(long iRowId) {
  Database.Result result = Database.Result.errUnknown;
  if (getUserDb().isOpened()) {
   if (getUserDb().tableExists(getTableName())) {
    long lRowsDeleted = deleteDataRow(iRowId);
    if (lRowsDeleted == 1) {
     result = Database.Result.Success;
    } else {
     result = Database.Result.errCantDeleteData;
    }
   } else {
    result = Database.Result.errTableNotExists;
   }
  } else {
   result = Database.Result.errNoDbAccess;
  }
  return result;
 }

 public Database.Result getRowDataForEdit(long lRowId) {
  Database.Result result = Database.Result.errUnknown;
  // get requested data row
  Cursor cr = locateDataRow(lRowId);
  if (cr == null) {
   result = Database.Result.errCantGetData;
  } else {
   if (cr.getCount() > 0) {
    if (dataRow.getValuesFromCursor(cr)) {
     try {
      dataRow.getValuesFromDataRow();
     } catch (Exception e) {
      return Database.Result.errCantGetValuesFromDataRow;
     }
     result = Database.Result.Success;
    } else {
     result = Database.Result.errCantGetDataFromTable;
    }
    cr.close();
   } else {
    result = Database.Result.errCantFindData;
   }
  }
  return result;
 }
}

Trên đây là toàn bộ kinh nghiệm làm việc với Database mà tôi học được trong quá trình làm việc thực tế. Mong giúp đỡ những người mới làm việc với SQLite trên Android. Chúc các bạn thành công

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

Tiếp tục tôi sẽ chỉ các bạn tạo một thể hiện của một dòng dữ liệu.
Mỗi một bảng trong SQLite nên tạo một thể hiện kế thừa từ lớp DataRow này.
Một DataRow chứa một số các DataField nên ta khai báo một mảng DataField.
Ngoài ra ta cần phải khai báo một biến trung ContentValues và một thể hiện Database ta đã tạo ở phần 1

package com.tannm.doan.taskmanager.database;

import android.content.ContentValues;
import android.database.Cursor;

public abstract class DataRow {
 // fields
 protected Database userdb = null;
 private DataField[] vecTableDef = null;
 private ContentValues values = new ContentValues();

 // methods
 public DataRow(Database userdb) {
  this.userdb = userdb;
 }

 public Database getUserDb() {
  return userdb;
 }

 public void setTableDefinition(DataField[] vecTableDef) {
  this.vecTableDef = vecTableDef;
  // initialize field parent
  updateDataFieldsParentRow(this);
 }

 public void updateDataFieldsParentRow(DataRow row) {
  for (int i = 0; i < vecTableDef.length; i++)
   vecTableDef[i].setParentRow(row);
 }

 public void copyTableDefinition(DataRow data) {
  setTableDefinition(data.vecTableDef);
 }

 public DataField[] getTableDef() {
  return vecTableDef;
 }

 public boolean validate() {
  return false;
 }

 public void clearContentValues() {
  values.clear();
 }

 public ContentValues getContentValues() {
  return values;
 }

 public void setContentValues(ContentValues values) {
  this.values = values;
  updateDataFieldsParentRow(this);
 }

 public boolean copyContentValues(ContentValues values) {
  this.values = values;
  updateDataFieldsParentRow(this);
  try {
   getValuesFromDataRow();
   return true;
  } catch (Exception e) {
  }
  return false;
 }

 public DataField value(int idx) {
  return vecTableDef[idx];
 }

 public String fieldName(int idx) {
  return vecTableDef[idx].getName();
 }

 public boolean getValuesFromCursor(Cursor cr) {
  if ((cr != null) && (cr.getPosition() != -1)) {
   for (int idx = 0; idx < vecTableDef.length; idx++) {
    DataField field = value(idx);
    // check if null value
    if (cr.isNull(idx)) {
     field.setNull();
    } else {
     final DataField.Type t = field.getType();
     // parse value by type
     if (t == DataField.Type.INT)
      field.set(cr.getLong(idx));
     if (t == DataField.Type.TEXT)
      field.set(cr.getString(idx));
     if (t == DataField.Type.BOOL)
      field.set((cr.getInt(idx) == 1) ? true : false);
    }
   }
   return true;
  }
  return false;
 }

 // sets fields values data (ContentValues values contener) from parent
 // object fields
 public abstract void setValuesForDataRow();

 // gets data from fields values (ContentValues values contener) to parent
 // object fields
 public abstract void getValuesFromDataRow();

 public abstract String getTableName();

}

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)

Friday, January 8, 2010

Lập trình database trên android

Để các bạn lập trình được với các ứng dụng cần dùng đến cơ sở dữ liệu trên android mình xin giới thiệu với các bạn sơ qua về lập trình database trên android:
Thật tuyệt vời khi mà trên android OS đã hỗ trợ chúng ta SQLite:
1, Việc đầu tiên bạn cần làm với database là tạo một cơ sở dữ liệu: Ở đây nó chỉ là một file cơ sở dữ liệu:
private final String MY_DATABASE_NAME = "myAndroidDB";
private final String MY_DATABASE_TABLE = "Member";
SQLiteDatabase myDB = null;
try {
/* Create the Database (no Errors if it already exists) */
this.createDatabase(MY_DATABASE_NAME, 1, MODE_PRIVATE, null);



2, Bạn đã tạo database roài giờ mở nó thế nào nhỉ:

/* Open the DB and remember it */
myDB = this.openDatabase(MY_DATABASE_NAME, null);



3, Tiếp đến bạn tạo một table đơn giản:

/* Create a Table in the Database. */
myDB.execSQL("CREATE TABLE IF NOT EXISTS "
+ MY_DATABASE_TABLE
+ " (LastName VARCHAR, FirstName VARCHAR,"
+ " Country VARCHAR, Age INT(3));");



4, Giờ ta insert thử vào database xem sao nhỉ

/* Add two DataSets to the Table. */
myDB.execSQL("INSERT INTO "
+ MY_DATABASE_TABLE
+ " (LastName, FirstName, Country, Age)"
+ " VALUES ('Nguyễn', 'Tân', 'VietNam', 24);");
myDB.execSQL("INSERT INTO "
+ MY_DATABASE_TABLE
+ " (LastName, FirstName, Country, Age)"
+ " VALUES ('Nguyễn', 'Dung', 'VietNam', 23);");



5, Có dữ liệu roài giờ truy vấn thử xem sao nhỉ:

/* Query for some results with Selection and Projection. */
Cursor c = myDB.query("SELECT FirstName,Age" +
" FROM " + MY_DATABASE_TABLE
+ " WHERE Age > 10 LIMIT 7;",
null);



6, Sử dụng hàm getColumnIndex(String) để lấy thông tin nhé:

/* Get the indices of the Columns we will need */
int firstNameColumn = c.getColumnIndex("FirstName");
int ageColumn = c.getColumnIndex("Age");

/* Check if our result was valid. */
if (c != null) {
/* Check if at least one Result was returned. */
if (c.first()) {
int i = 0;
/* Loop through all Results */
do {
i++;
/* Retrieve the values of the Entry
* the Cursor is pointing to. */
String firstName = c.getString(firstNameColumn);
int age = c.getInt(ageColumn);
/* We can also receive the Name
* of a Column by its Index.
* Makes no sense, as we already
* know the Name, but just to shwo we can Wink */
String ageColumName = c.getColumnName(ageColumn);

/* Add current Entry to results. */
results.add("" + i + ": " + firstName
+ " (" + ageColumName + ": " + age + ")");
} while (c.next());
}
}


7, Sau khi làm việc với database bạn hãy đóng nó lại nhé:

} catch (FileNotFoundException e) {
} finally {
if (myDB != null)
myDB.close();
}



8, Cuối cùng bạn lấy thông tin ra roài giờ hiển thị nó thui nhỉ:
this.setListAdapter(new ArrayAdapter(this,
android.R.layout.simple_list_item_1_small, results));
}
}