Android cung cấp cho bạn một số lựa chọn để lưu trữ dữ liệu của ứng dụng một cách rất bền vững. Các giải pháp lưu trữ tùy thuộc vào phụ thuộc vào sự lựa chọn của bạn và chương trình của bạn đang phát triển.
• Shared Storage: Dữ liệu của bạn sẽ được lưu trữ dưới dạng cặp khóa-giá trị, đây là cách lưu trữ truyền thống trên di động. Chúng ta muốn lưu trữ UI state, user preferences hay application setting thì đây là một cơ chế gọn nhẹ để lưu trữ.
• File: Android cho phép chúng ta tải và lưu các tệp tin trên thiết bị di động.
• SQLite Databases: Lưu trữ dữ liệu dưới dạng một cấu trúc mà bạn xây dựng sẵn trong một cơ sở dữ liệu riêng. Cách này thường được dùng nhiều trong android để xây dưng các ứng dụng
• Network Connection: Dữ liệu sẽ được chia sẻ và lưu trữ trên web thông qua máy chủ dữ liệu của bạn.
• Ngoài ra, android cung cấp cho bạn một cách để chia sẻ các dữ liệu cá nhân của ứng dụng cho các ứng dụng khác thông qua Content Provider. Chúng ta có thể truy cập Content Provider để sử dụng hệ thống được phép.
34 trang |
Chia sẻ: lvbuiluyen | Lượt xem: 2359 | Lượt tải: 3
Bạn đang xem trước 20 trang tài liệu Seminar Subject: Data Storage in Android, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN
KHOA CÔNG NGHỆ PHẦN MỀM
Seminar Subject: Data Storage in Android
Giáo viên hướng dẫn: Cáp Phạm Đình Thăng.
Sinh viên thực hiện:
Nguyễn Văn Sinh 105020130
Tôn Ngọc Tẩn 10520133
Contents
Giới thiệu về cách lưu trữ trên android:
Android cung cấp cho bạn một số lựa chọn để lưu trữ dữ liệu của ứng dụng một cách rất bền vững. Các giải pháp lưu trữ tùy thuộc vào phụ thuộc vào sự lựa chọn của bạn và chương trình của bạn đang phát triển.
Shared Storage: Dữ liệu của bạn sẽ được lưu trữ dưới dạng cặp khóa-giá trị, đây là cách lưu trữ truyền thống trên di động. Chúng ta muốn lưu trữ UI state, user preferences hay application setting thì đây là một cơ chế gọn nhẹ để lưu trữ.
File: Android cho phép chúng ta tải và lưu các tệp tin trên thiết bị di động.
SQLite Databases: Lưu trữ dữ liệu dưới dạng một cấu trúc mà bạn xây dựng sẵn trong một cơ sở dữ liệu riêng. Cách này thường được dùng nhiều trong android để xây dưng các ứng dụng
Network Connection: Dữ liệu sẽ được chia sẻ và lưu trữ trên web thông qua máy chủ dữ liệu của bạn.
Ngoài ra, android cung cấp cho bạn một cách để chia sẻ các dữ liệu cá nhân của ứng dụng cho các ứng dụng khác thông qua Content Provider. Chúng ta có thể truy cập Content Provider để sử dụng hệ thống được phép.
Shared Storage:
Lớp Shared Preferences cung cấp một khuôn khổ chung cho phép bạn lưu trữ và lấy cặp giá trị dưới dạng key-value. Bạn có thể sử dụng Shared Preferences để lưu bất kì kiểu dữ liệu mặc định nào: Booleans, floats, ints, longs hoặc strings. Dữ liệu này sẽ tồn tại suốt phiên làm việc của người dùng (ngày cả khi ứng dụng của bạn có bị đóng đi).
Ưu điểm:
Dữ liệu lưu trữ chỉ dành riêng cho ứng dụng mà nó được viết ra.
Được coi là một phần thông tin của hệ thống.
Tính bảo mật rất cao.
Nhược điểm:
Không thể lấy thông tin dữ liệu dưới dạng file.
Dung lượng bộ nhớ lưu trữ thấp nên chỉ phù hợp với việc lưu trữ thông tin cấu hình.
Sử dụng một đối tượng Editor để lưu dữ liệu. Để có được một đối tượng SharedPreferences cho các ứng dụng của bạn, hãy sử dụng một trong hai phương thức:
getSharedPreferences (): Sử dụng nó nếu bạn cần nhiều tập tin tham chiếu được xác định theo tên, mà bạn chỉ định với tham số đầu tiên.
getPreferences () : Sử dụng điều này nếu bạn chỉ cần một tham chiếu đến tập tin cho hoạt động của bạn. Vì có duy nhất một tập tin tham chiếu cho active của bạn, bạn không cần cung cấp tên.
//ten cua SharedPreferences
private static final String CONFIGURATION_NAME = "NAME_CONFIG";
Tạo và lưu giá trị vào SharePreferences:
Để ghi giá trị vào trong bộ nhớ bạn cần sử dụng một đối tượng editor:
Gọi một editor thông qua SharedPreference.Editor.
Thêm các giá trị vào bộ nhớ đệm bằng các hàm putString(), putInt(), putBoolean().
Đẩy giá trị vào bộ nhớ bằng hàm editor.comit().
Code:
btSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//lấy tên của người dùng nhập trong EditText name.
String name = edtName.getEditableText().toString().trim();
//lấy id của người dùng nhập trong EditText id.
String id = edtID.getEditableText().toString().trim();
//tạo một đối tượng SharedPreferences ở chế độ MODE_PRIVATE.
SharedPreferences editPreference = getSharedPreferences(CONFIGURATION_NAME, Activity.MODE_PRIVATE);
//lay doi tuong Editor dung de luu du lieu vao bo nho
Editor editor = editPreference.edit();
//day du lieu voi cap khoa-gia tri la id-name va bo nho phu
editor.putString(id, name);
//day du lieu tu bo nho phu vao bo nho thiet bi
editor.commit();
}
});
Truy xuất giá trị từ SharePreferences:
Để truy cập Shared Preferences thì cũng dùng phương thức getSharedPreferences, đưa vào khóa của dữ liệu trong SharedPreferences mà chúng ta muốn truy cập, dùng phương thức SharedPreferences.getString (),SharedPreferences.getInt(), …để truy xuất giá trị cần thiết.
Code:
btLoad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//lay id ma nguoi dung nhap thong qua edtID de lay du lieu ra
String id = edtID.getEditableText().toString().trim();
//lay doi tuong SharedPreferences thong qua ten va che do Activity.
SharedPreferences editPreference =
getSharedPreferences(CONFIGURATION_NAME,Activity.MODE_PRIVATE);
//lay du lieu voi 2 tham so la: id va gia tri xuat ra khi khong co roi sau do set cho edtName
edtName.setText(editPreference.getString(id,CONFIGURATION_NAME));
}
});
Toàn bộ source code và demo nằm trong thư mục DemoSeminar/Seminar_Share
Lưu và đọc các tập tin trong android:
Cũng như các tiêu chuẩn I/O của java thì trong android cũng cung cấp openFileInput và openFileOutput để đơn giản các công việc ghi và đọc trên các dòng hoặc các file.
Ưu điềm:
Xử lí trên file đơn giản.
Đọc file và lưu trữ file có thể ở nhiều định dạng.
Dung lượng file không giới hạn như cách lưu trữ SharePreferences
Nhược điểm:
Không có tính bảo mật cao.
Có thể bị lỗi khi xung đột file hoặc xung đột luồng đọc file.
Các lớp tiện ích để xử lí file nằm trong gói Android.os.Enviroment
Để xử lí các thao tác trên file được tốt ta nên xử dụng các lớp nằm trong gói java.os
File: Thao tác xử lí file.
FileInputStream: đọc nội dung file.
FileOutputStream:Ghi nội dung file.
Đọc file:
Muốn đọc một file lên ta phải dung lớp FileInputStream để mở file và dùng lớp InputStreamReader để mở một dòng đọc file.
Code:
private String readFile() throws IOException
{
//doc ten cua file tu edtFilePath
FILE_NAME = edtFilePath.getEditableText().toString().trim();
//mo mot file len de doc
FileInputStream ios = openFileInput(FILE_NAME);
//mot kenh truu tuong hoa dung de doc cac dinh dang dau vao
//trong truong hop nay la file
InputStreamReader isr= new InputStreamReader(ios);
//tao mot mang dung de doc du lieu nhan duoc tu file
char[] data = new char[1024];
//dung StringBuffer de nhan du lieu tu file ra
StringBuffer strBuffer = new StringBuffer();
int len = 0;
//khi chua ket thuc file thi doc du lieu vao strBuffer
while((len = isr.read(data)) != -1)
{
strBuffer.append(new String(data, 0, len));
}
//dong file va dong kenh doc file
isr.close();
ios.close();
//tra ve chuoi du lieu trong file
return strBuffer.toString();
}
Ghi file:
Muốn đọc một file lên ta phải dung lớp FileOutputStream để mở file và dùng lớp OutputStreamWriter để mở một dòng đọc file.
Có nhiều chế độ để mở file để ghi là:
Context.MODE_PRIVATE: đọcfile mà dữ liệu cũ của file bị ghi đè bởi dữ liệu mới.
Context.MODE_APPEND: đọcfile mà dữ liệu mới của file được ghi tiếp tục dưới dữ liệu cũ.
private void writeFile(String inText) throws IOException
{
//lay ten file tu edtFilePath
FILE_NAME = edtFilePath.getEditableText().toString().trim();
//mo mot file neu co hoac tao mot file moi neu chua co
FileOutputStream fos = openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
//mo mot luong(kenh) du lieu de ghi vao files
OutputStreamWriter osw = new OutputStreamWriter(fos);
//chi viet ra mot bo dem trong thiet bi di dong
osw.write(inText + "\n");
//day vao file can luu
osw.flush();
//dong file va kenh du lieu
osw.close();
fos.close();
}
Kiểm tra thiết bị ngoại vi để lưu trữ file:
Android có thể giúp bạn kiểm tra một thiết bị SD-Card có đang được hỗ trợ để lưu dữ liệu hay không.
Ta dùng lớp Enviroment để kiểm tra và lấy trạng thái của môi trường.
Code:
private boolean hasSDCard()
{
//kiem tra co ho tro the SDCard ben ngoai hay khong
//lay trang thai cua bo nho ngoai SDCard, tra ve trang thai duoi dang chuoi
String state = Environment.getExternalStorageState();
//kiem tra da duoc dua vao he thong hay chua
if(state.equals(Environment.MEDIA_MOUNTED))
{
return true;
}
return false;
}
Bạn làm việc trên file nên sẽ ném ra các ngoại lệ IOException, ta sẽ xử dụng hàm try catch để bắt lỗi. Tất cả các demo và source code nằm trong DemoSeminar/Seminar_FileDemo.
Cơ sở dữ liệu trong Android:
Android cung cấp đầy đủ các quan hệ cơ sở dữ liệu thông qua thư viện SQLite mà không áp đặt bất kì hạn chế nào lớn. Sử dụng SQLite có thể tạo cơ sở dữ liệu quan hệ độc lập cho mỗi ứng dụng.
Tất cả các cơ sở dữ liệu trong android được lưu trong thư mục /data/data//databases để chia sẻ cơ sở dữ liệu qua các ứng dụng ta dùng Context Provider (ở phần sau).
Giới thiệu về SQLite:
SQLite là một bản SQL sever less của SQL database engine.
Nhẹ gọn và linh hoạt với dung lượng khoảng 300kb(chiếu trong kho ứng dụng của thiết bị)
Đa nền tảng và không cần cấu hình mạnh.
Không hỗ trợ một số tính năng ví dự như quản lí user sử dụng, không có khóa ngoại, không có các ràng buộc toàn vẹn…
Lưu trữ tại data/data//database
Các lớp cơ bản khi sư dụng SQLite:
Lớp SQLiteOpenHelper:
Giới thiệu:
SQLiteOpenHelper là lớp quản lí việc kết nối, tạo và quản lí cơ sở dữ liệu cũng như phiên bản của cơ sở dữ liệu.
Đối tượng của lớp này cần tham chiếu đến một đối tượng Context. Mỗi database được tạo ra nằm trong một ứng dụng riêng nên để quản lí chúng ta cần phải chuyền vào ngữ cảnh Context đề SQLiteOpenHelper nhận biết và quản lí.
Cách tốt nhất đề sử dụng lớp này là chúng ta tạo ra một lớp mới kế thừa các phương thức của SQLiteOpenHelper để dễ sử dụng như ví dụ sau:
Các phương thức:
Hàm khởi tạo:
SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version), gồm có 4 tham số truyền vào là:
Context context : ngữ cảnh Context hiện tại
SQLiteDatabase.CursorFactory factory: dùng để cho phép các lớp con được trả về con trỏ cursor khi gọi câu query
String name: tên của database.
int version: phiên bản của database.
Các phương thức ảo được mặc định kế thừa trong lớp mới:
Void onCreate(SQLiteDatabase db), được gọi khi database được tạo lần đầu tiên với tham số:
SQLiteDatabase db: đối tượng dùng để quản lí các công việc của database.
void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),được gọi khi cần update phiên bản cho database, gồm các tham số sau:
Các phương thức khác:
SQLiteDatabase db: đối tượng quản lí các công việc của database.
int oldVersion: phiên bản cũ của database.
int newVersion: phiên bản mới của database.
onOpen(SQLiteDatabase db), gọi một đối tượng SQLiteDatabase khi cần thiết (ít sử dụng).
close(): đóng đối tượng SQLiteOpenHelper.
String getDatabaseName(): trả về tên của database.
SQLiteDatabase getReadableDatabase() mở database hiện hành để đọc.
SQLiteDatabase getWritableDatabase() mở database hiện hành đề đọc và ghi.
Lớp SQLiteDatabase:
Giới thiệu:
Là đối tượng đại diện cho cơ sở dữ liệu mà ta tạo ra bởi đối tượng SQLiteOpenHelper.
Tên của database trong một ứng dụng là duy nhất.
Là đối tượng trực tiếp để thực thi các câu lệnh SQL và các công việc cần thực hiện trên các table của database.
Các phương thức:
void execSQL(String sql): thực thi câu lệnh sql thông thường, không trả về kết quả.
Long insert(String table, String nullColumnHack, ContentValues values), chèn dữ liệu vào một table. Tham số:
String table: tên của table cần chèn dữ liệu.
String nullColumnHack: thường để null.
ContentValues values: đối tượng chứa dữ liệu chèn vào.
int delete(String table, String whereClause, String[] whereArgs) : phương thức dùng để xóa các hàng trong cơ sở dữ liệu. Tham số:
String table: tên của table trong cơ sở dữ liệu.
String whereClause: câu lệnh điều kiện cần để thực hiện câu delete (mện đề WHERE).
String[] whereArgs: mảng tham số cần để thực hiện delete.
Trả về số dòng đã bị xóa trong cơ sở dữ liệu.
Cursor rawQuery(String sql, String[] selectionArgs): chạy câu lệnh sql và trả về một đối tượng cursor (sẽ nói ở phần sau). Tham số:
String sql: câu lệnh sql.
String[] selectionArgs: tham số cần truyền vào trong câu truy vấn.
Lớp Cursor:
Giới thiệu:
Là một đối tượng trả về từ phương thức của họ Query.
Hành động như một con trỏ đến tập hợp các giá trị dữ liệu nằm dưới cơ sở dữ liệu mà ta đã xác định thông qua các câu lện trong SQLiteDatabase.
Quản lí và kiểm soát các dòng dữ liệu (row) trong tập kết quả truy vấn của cơ sở dữ liệu.
Các phương thức:
Boolean moveToFirst(): di chuyển con trỏ đến dòng dữ liệu đầu tiên, thành công trả về true, ngược lại là false
Boolean moveToLast(): di chuyển con trỏ dữ liệu đến dòng cuối cùng, thành công trả về true, ngược lại là false.
Boolean moveToNext(): di chuyển con trỏ đến dòng dữ liệu kế tiếp, thành công trả về true, ngược lại là false.
Boolean moveToPrevious(): di chuyển con trỏ đến dòng dữ liệu trước đó, thành công trả về true, ngược lại là false.
Boolean moveToPosition(int position): di chuyển con trỏ dữ liệu đến dòng tại vị trí position, thành công trả về true, ngược lại là false.
Boolean isFirst(): kiểm tra coi con trỏ tại vị trí dòng đầu tiên.
Boolean isLast(): kiểm tra coi con trỏ có đang ở tại vị trí dòng cuối cùng.
Boolean isNull(int columnIndex): Trả về true nếu giá trị trong cột chỉ định là null.
Int getCount(): trả về số dòng dữ liệu của câu truy vấn query.
Int getPosition(): trả về vị trí hiện tại của con trỏ cursor tại dòng nào.
Int getType(int columnIndex): trả về kiểu dữ liệu tại cột có chỉ số columIndex.
String getColumnName(int columnIndex): trả về tên của cột tại vị trí chỉ định.
String[] getColumnNames(): trả về tên của các cột.
Int getColumnIndex(String columnName): trả về chỉ số của cột có tên là columnName.
Int getColumnCount(): trả về số cột có trong dữ liệu này.
Và còn nhiều phương thức khác, bạn có thể xem thêm trên
Ví dụ demo về quản lí thông tin một người.
Lớp DTOPeople:
Để quản lí việc nhận dữ liệu từ GUI và chuyển dữ liệu vào database được dễ dàng và thuận tiện, không gây khó chịu cho việc viết code chúng ta cần xây dựng một lớp gọi là DTOPeople (Tổ chức theo mô hình 3 lớp). Lớp này là một lớp trừu tượng hóa các thông tin của con người cần đưa vào cơ sở dữ liệu. Sau đây là code:
public class DTOPeople {
private int gID;
private String gName;
private String gPhone;
private String gEmail;
private String gAddress;
public int getgID() {
return gID;
}
public void setgID(int gID) {
this.gID = gID;
}
public String getgName() {
return gName;
}
public void setgName(String gName) {
this.gName = gName;
}
public String getgPhone() {
return gPhone;
}
public void setgPhone(String gPhone) {
this.gPhone = gPhone;
}
public String getgEmail() {
return gEmail;
}
public void setgEmail(String gEmail) {
this.gEmail = gEmail;
}
public String getgAddress() {
return gAddress;
}
public void setgAddress(String gAddress) {
this.gAddress = gAddress;
}
public DTOPeople()
{
gID = 0;
gName = "Nguyen Van Sinh";
gEmail = "Royalknight2902@gmail.com";
gPhone = "01264721476";
gAddress = "Ho Chi Minh";
}
public DTOPeople(int mID, String mName, String mEmail,
String mPhone, String mAddress)
{
gID = mID;
gName = mName;
gEmail = mEmail;
gPhone = mPhone;
gAddress = mAddress;
}
public String displayPeople()
{
String temp = "";
temp += String.valueOf(gID).toString().trim() + "\n";
temp += gName.toString().trim() + "\n";
temp += gEmail.toString().trim() + "\n";
temp +=gPhone.toString().trim() + "\n";
temp += gAddress.toString().trim();
return temp;
}
}
Lớp DAOPeople:
Lớp này sẽ hiện thực hóa và kế thừa lớp SQLiteOpenHelper dùng để tạo và quản lí kết nối tới database.
Đầu tiên bạn cần tạo tên của database, tên của table có trong database, câu lệnh tạo bảng và đối tượng SQLDatabase để sử dụng trong toàn bộ lớp. Sau đây là Code phần này:
//ten cua database
private static String database_name = "INFOPEOPLE";
//ten cua mot bang nam trong database
private static String table_name = "PEOPLE";
//cau truc tao ra bang table_name
private static String table_create = "CREATE TABLE [" + table_name +"] (" +
"[ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
"[Name] TEXT NOT NULL," +
"[Email] TEXT NULL," +
"[Phone] TEXT NULL," +
"[Address] TEXT NULL)";
//phien ban cua database
private static int database_version = 1;
//doituong SQLiteDatabase dung de thuc hien cac cau len SQL
private SQLiteDatabase gdb;
Sau đó bạn cần tạo database, table và tạo hàm update database:
//hàm khởi tạo dùng để tạo database với đối số truyền vào là Context.
public DAOPeople(Context context) {
super(context, database_name, null, database_version);
}
//hàm onCreate dùng để tạo bảng trong database
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(table_create);
}
//update phien ban cua database
@Override
public void onUpgrade(SQLiteDatabase db, int version_old, int version_new) {
Log.w(DAOPeople.class.getName(),
"Upgrading database from version " + version_old + " to "
+ version_new + ", which will destroy all old data");
gdb.execSQL("DROP TABLE IF EXISTS " + table_name);
db.execSQL(table_create);
}
Tiếp theo bạn sẽ tạo hàm thêm dữ liệu vào database, lớp này nhận thông tin qua một đối tượng DTOPeople. Chúng ta cần mở database dưới dạng đọc và ghi theo code sau:
gdb = this.getWritableDatabase();
.Sau đây là code:
//thêm thông tin của một người vào database
public void addPeople(DTOPeople mPeople)
{
//mo database duoi dang doc va ghi
gdb = this.getWritableDatabase();
//cau lenh sql
String str = "INSERT INTO " + table_name + "(Name,Email,Phone,Address) VALUES(";
str += "'" + mPeople.getgName().toString().trim() + "',";
str += "'" + mPeople.getgEmail().toString().trim() + "',";
str += "'" + mPeople.getgPhone().toString().trim() + "',";
str += "'" + mPeople.getgAddress().toString().trim() + "')";
//thuc hien cau lenh sql thong qua doi tuong SQLDatabase
gdb.execSQL(str);
gdb.close();
}
Tiếp theo bạn sẽ tạo hàm sửa dữ liệu trong database, lớp này cũng nhận những thông tin cần sửa chữa qua một đối tượng DTOPeople. Sau đây là code:
//hàm sửa dữ liệu có trong database
public void updatePeople(DTOPeople mPeople)
{
//mo database duoi dang doc va ghi
gdb = this.getWritableDatabase();
//cau lenh sql
String str = "UPDATE " + table_name + " SET ";
str += "Name = '" + mPeople.getgName().toString().trim() + "',";
str += "Email = '" + mPeople.getgEmail().toString().trim() + "',";
str += "Phone = '" + mPeople.getgPhone().toString().trim() + "',";
str += "Address = '" + mPeople.getgAddress().toString().trim() + "' ";
str += "WHERE ID = " + mPeople.getgID();
//thuc hien cau lenh sql thong qua doi tuong SQLDatabase
gdb.execSQL(str);
gdb.close();
}
Sau đó bạn sẽ tạo hàm delete dữ liệu có trong database dưới dạng id. Bạn cũng có thể xây dựng hàm delete hay update dưới dạng tên hay theo số điện thoại tùy vào mong muốn sử dụng của bạn và bạn chỉ cần thay đổi tham số truyền vào cũng như cấu trúc của câu lệnh sql. Sau đây là code:
//ham xoa mot dong trong bang voi id duoc dua vao
public void deletePeople(int id)
{
//mo database duoi dang doc va ghi
gdb = this.getWritableDatabase();
//cau lenh sql
String str = "DELETE FROM " + table_name + " WHERE ID = " + id;
//thuc hien cau lenh sql thong qua doi tuong SQLDatabase
gdb.execSQL(str);
gdb.close();
}
Sau đây là các hàm lấy thông tin từ cơ sở dữ liệu để đưa ra bên ngoài. Đầu tiên là hàm lấy một dòng dữ liệu với tham số truyền vào là id của dữ liệu, đối tượng trả ra là DTOPeople:
//lay thong tin cua mot nguoi voi id duoc nhap vao
//return ve duoi dang doi tuong DTOPeople
public DTOPeople getPeople(int id)
{
//mo database duoi dang doc
gdb = this.getReadableDatabase();
//tao mot doi tuong DTOPeople de luu thong tin cua nguoi nay
//sau do return gia tri
DTOPeople mPeople = new DTOPeople();
//cau lenh sql
String str = "SELECT * FROM " + table_name + " WHERE ID = " + id;
//tra ve con tro Cursor tro den du lieu ma chung ta da lay ra thong qua cau len sql
Cursor cur = gdb.rawQuery(str, null);
//kiem tra con tro cursor co du lieu hay khong
//neu khong co thi return ve null
if(cur.moveToFirst() == false)
{
cur.close();
gdb.close();
return null;
}
//co du lieu trong con tro cursor thi
//lay