Seminar Subject: Data Storage in Android

• Để xây dựng một Content Provider cho ứng dụng của mình bạn cần hiện thực và kế thừa từ một lớp có sẵn là contentProvider trong Android. • Override tất cả các phương thức sau: o onCreate(): khởi tạo một ứng dụng được bạn cung cấp. Hệ thống Android gọi phương thức này ngay sau khi nó tạo ra ứng dụng được bạn cung cấp. Chú ý rằng, ứng dụng được bạn cung cấp sẽ không được tạo ra cho đến khi có một đối tượng ContentResolver được truy cập. o getType(): trả về định dạng MIME tương ứng với nội dung của một URI. Phương thức này sẽ được nói rõ hơn trong phần thực thi của Content Provider ở sau. o insert(): chèn một dòng dữ liệu mới vào ứng dụng được bạn cung cấp. Trả về một định dạng URI cho dòng mới thêm vào. o update(): cập nhật dòng dữ liệu hiện đang có trong ứng dụng được bạn cung cấp. Trả về số dòng được cập nhật. o delete(): xóa dòng dữ liệu trong Provider của bạn. Trả về số dòng được xóa. o query(): lấy dữ liệu từ Provider của bạn. Trả về dữ liệu dưới dạng một con trỏ Cursor.

docx33 trang | Chia sẻ: lylyngoc | Lượt xem: 2807 | Lượt tải: 0download
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 du lieu trong dua vao trong doi tuong DTOPeople de dua ra ngoai else { //vi tri cua cac cot trong du lieu giong nhu khi ta tao bang //ID la kieu int nen chung ta getInt mPeople.setgID(cur.getInt(0)); //tuong tu, cac truong con lai la String nen chung ta getString mPeople.setgName(cur.getString(1).toString().trim()); mPeople.setgEmail(cur.getString(2).toString().trim()); mPeople.setgPhone(cur.getString(3).toString().trim()); mPeople.setgAddress(cur.getString(4).toString().trim()); cur.close(); gdb.close(); return mPeople; } } Tiếp theo là hàm lấy toàn bộ dữ liệu có trong bảng. Sau đây là code: //ham lay tat ca du lieu trong table_name public DTOPeople[] getAllPeople() { //mo database duoi dang doc gdb = this.getReadableDatabase(); //cau lenh sql dem so dong du lieu co trong table_name String sql = "SELECT COUNT(*) FROM " + table_name; //cau lenh sql lay toan bo du lieu trong table_name String str = "SELECT * FROM " + table_name; //thuc hien cau lenh dem so dong du lieu co trong table_name Cursor cur = gdb.rawQuery(sql, null); //kiem tra con tro cursor co du lieu hay khong if(cur.moveToFirst()) { //lay so dong du lieu co trong table, //doi tuong nay dung de duyet sau nay, giup chung ta lay toan bo du lieu int len = cur.getInt(0); //neu so dong du leu nho hon hoac bang 0 thi return ve null if(len <= 0) { cur.close(); gdb.close(); return null; } //neu so dong du lieu lon hon 0 (ton tai du lieu) thi thuc hien viec lay du lieu else { //thuc hien cau lenh lay toan bo du lieu co trong table_name cur = gdb.rawQuery(str, null); //neu con tro cursor khong co du lieu (loi) thi tra ve null if(cur.moveToFirst() == false) { cur.close(); gdb.close(); return null; } else { int count = 0; //tao mot mang doi tuong DTOPeople de lay du lieu DTOPeople[] listPeople = new DTOPeople[len]; do { listPeople[count] = new DTOPeople(); listPeople[count].setgID(cur.getInt(0)); listPeople[count].setgName(cur.getString(1).toString().trim()); listPeople[count].setgEmail(cur.getString(2).toString().trim()); listPeople[count].setgPhone(cur.getString(3).toString().trim()); listPeople[count].setgAddress(cur.getString(4).toString().trim()); count++; } while (cur.moveToNext()); cur.close(); gdb.close(); return listPeople; } } } else { cur.close(); gdb.close(); return null; } } Lớp MainActivity: Lớp này là lớp giao tiếp giữa việc đưa dữ liệu vào lớp DAOPeople và giao diện người dùng. Đầu tiên, chúng ta cần tạo các đối tượng để hỗ trợ cho lớp này thực hiện các thao tác. private DAOPeople daoPeople; private DTOPeople dtoPeople; //cac Button de xu li xu kien private Button btSave; private Button btUpdate; private Button btDelete; private Button btShow; private Button btDisplay; //cac EditText de nhan du lieu tu nguoi dung nhap private EditText edtID; private EditText edtName; private EditText edtEmail; private EditText edtPhone; private EditText edtAddress; private ListView lvShow; Sau đó là tạo các hàm cơ bản để thao tác với đối tượng DAOPeople. Hàm lấy dữ liệu từ giao diện và thêm vào cơ sở dữ liệu: //them mot du lieu vao co so du lieu private void onSave() { //lay du lieu tu man hinh GUI va dua vao doi tuongDTOPeople dtoPeople.setgName(edtName.getEditableText().toString().trim()); dtoPeople.setgEmail(edtEmail.getEditableText().toString().trim()); dtoPeople.setgPhone(edtPhone.getEditableText().toString().trim()); dtoPeople.setgAddress(edtAddress.getEditableText().toString().trim()); daoPeople.addPeople(dtoPeople); } Hàm sửa dữ liệu trong database: //sua du lieu trong co so du lieu private void onUpdate() { //lay du lieu tu man hinh GUI va dua vao doi tuongDTOPeople dtoPeople.setgID(Integer.parseInt(edtID.getEditableText().toString().trim())); dtoPeople.setgName(edtName.getEditableText().toString().trim()); dtoPeople.setgEmail(edtEmail.getEditableText().toString().trim()); dtoPeople.setgPhone(edtPhone.getEditableText().toString().trim()); dtoPeople.setgAddress(edtAddress.getEditableText().toString().trim()); daoPeople.updatePeople(dtoPeople); } Hàm xóa dữ liệu: //xoa du lieu trong co so du lieu private void onDelete() { if(edtID.getEditableText().toString().trim() != null) { //neu co nhap id thi lay id tu man hinh giao dien ma nguoi dung nhap int id = Integer.parseInt(edtID.getEditableText().toString().trim()); daoPeople.deletePeople(id); } else { //neu nguoi dung khong nhap id thi mac dinh xoa ban ghi dau tien int id = daoPeople.getAllPeople()[0].getgID(); daoPeople.deletePeople(id); } } Hàm hiện thị dữ liệu với id được nhập vào lên trên giao diện cho người dùng biết: //hien thi thong tin du lieu voi mot id duoc nhap vao private void onShow() { if(edtID.getText() != null) { //lay id tu nguoi dung nhap int id = Integer.parseInt(edtID.getEditableText().toString().trim()); //lay doi tuong DTOPeople thong qua id dtoPeople = daoPeople.getPeople(id); //xuat tat ca cac truong len giao dien cho nguoi dung nhin thay edtID.setText(String.valueOf(dtoPeople.getgID())); edtName.setText(dtoPeople.getgName().toString().trim()); edtEmail.setText(dtoPeople.getgEmail().toString().trim()); edtPhone.setText(dtoPeople.getgPhone().toString().trim()); edtAddress.setText(dtoPeople.getgAddress().toString().trim()); } else { //neu nguoi dung ko nhap id thi lay ban ghi dau tien int id = daoPeople.getAllPeople()[0].getgID(); dtoPeople = daoPeople.getPeople(id); edtID.setText(String.valueOf(dtoPeople.getgID())); edtName.setText(dtoPeople.getgName().toString().trim()); edtEmail.setText(dtoPeople.getgEmail().toString().trim()); edtPhone.setText(dtoPeople.getgPhone().toString().trim()); edtAddress.setText(dtoPeople.getgAddress().toString().trim()); } } Hiển thị toàn bộ thông tin dữ liệu lên ListView //hien thi toan bo thong tin du lieu len ListView private void onDisplay() { DTOPeople[] listPeople = daoPeople.getAllPeople(); int len = listPeople.length; String[] values = new String[len]; for(int i = 0; i < len; i++) { values[i] = listPeople[i].displayPeople().toString().trim(); } ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, values); //show du lieu len ListView lvShow.setAdapter(adapter); } Demo và source code của chương trình này nằm ở DemoSeminar/Seminar_SQLite Tìm hiều và sử dụng Content Provider: Tìm hiều về Content Provider: Content Provider là một thành phần cơ bản của Android SDK. Content Provider là một chuẩn giúp bạn chia sẻ dữ liệu giữa các ứng dụng trên Android: Là cách thức tiêu chuẩn để chia sẻ dữ liệu giữa các ứng dụng khác nhau.. Không phải là cách thức để lưu trữ dữ liệu trên Android. Call long, Contact List hoặc SMS có thể truy xuất bằng Content Provider. Content Provider đóng gói dữ liệu và cung cấp dữ liệu cho các ứng dụng thông qua giao diện ContentResolver duy nhất. Khi thực hiện yêu cầu thông qua ContentResolver thì hệ thông cần kiểm tra các chỉ định tài nguyên URI (Uniform Resource Identifier) mà nhà cung cấp đã đăng kí với hệ điều hành. Chỉ định URI sẽ được giải thích ở phần sau và lớp UriMatcher rất có ích cho việc phân tích chuỗi URI. Đối tượng trả về của Content Provider là đối tượng Cursor trỏ đến dữ liệu của ứng dụng. Mọi content provider, đều sử dụng chung 1 interface để tìm và trả về dữ liệu, bao gồm việc thêm, bớt và sửa dữ liệu. Việc này được thực hiện thông qua các đối tượng ContentResolver khi gọi getContentResolver(): ContentResolver cr = getContentResolver(); Để lấy đối tượng Cursor trỏ đến dữ liệu của ứng dụng chia sẻ bởi Content Provider ta sử hàm sau: getContentResolver().query(Uri uri) Tìm hiểu về URI: URI là đường dẫn đến dữ liệu mà Content Provider chia sẻ. Nội dung một chuối URI chuẩn: A – Tiền tố mặc định của 1 chuỗi URI chỉ ra dữ liệu được điều khiển bởi Content Provider và nó không thể thay đổi được. Chỉ đến nơi lưu trữ cơ sở dữ liệu. Giống như cấu trúc của một số điện thoại thì cái này giống mã quốc gia hoặc giống như tên của một cơ sở dữ liệu. Phần này chỉ ra loại dữ liệu. Chẳng hạn như dữ liệu contact, sms, ... Phần này có thể coi như tên của một table do bạn định nghĩa khi xây dựng Content Provider. Phần này chỉ đến đúng vị trí của dữ liệu. Phần này giống như id của dòng dữ liệu trong table hoặc một dòng dữ liệu khi xuất ra câu truy vấn. Ví dụ: content://contacts/people/0 Sử dụng một Content Provider có sẵn: Giới thiệu: Android cung cấp một tập hợp các Content Provider có sẵn trong tất cả các ứng dụng đã được xây dựng mặc định. Tập hợp những Content Provider này được nằm sẵn trong android.provider. Sử dụng định danh tài nguyên URI để truy xuất đến tài nguyên của cơ sở dữ liệu được chia sẻ Đối tượng trả về là con trỏ dạng Cursor. Để sử dụng Content Provider có sẵn bạn phải sử dụng uses-permission trong AndroidMainfast.xml. Ví dụ Demo: Sau đây mình sẽ demo về việc sử dụng một Content Provider có sẵn đề viết một ứng dụng nhỏ. Mình sẽ sử dụng Content Provider của Contact List (danh bạ điện thoại) để lấy ra tên và số điện thoại của thiết bị đang chạy ứng dụng này. Muốn sử dụng được Content Provider của Contact List bạn cần import thông tin sau: import android.provider.Contacts.Phones; Trong ứng dụng này, bạn cần lấy một Cursor để trỏ đến vùng dữ liệu của Contact List để lấy các thông tin mà chúng ta cần thông qua cách sau: //tra ve 1 cursor tro den tat ca cac ban ghi trong danh ba dien thoai //thông qua Phones_URI là đường dẫn của danh bạ điện thoai Cursor cur = getContentResolver().query(Phones.CONTENT_URI, null, null, null, null); //khởi động đối tượng cursor này startManagingCursor(cur); Ta lấy các thông tin về tên, số điện thoại của một bản ghi bằng cách sau: //tên của một người trong 1 bảng ghi danh bạ điện thoại Phones.NAME //số điện thoại của một người trong 1 bảng ghi danh bạ điện thoại Phones.NUMBER Và còn nhiều thông số khác mà bạn có thể lấy, tùy mục đích của bạn. public class MainActivity extends ListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //tra ve 1 cursor tro den tat ca cac ban ghi trong danh ba dien thoai Cursor cur = getContentResolver().query(Phones.CONTENT_URI, null, null, null, null); //khoi dong doi tuong cursor nay startManagingCursor(cur); //tao các đối tượng ListAdapter từ các dữ liệu mà mình muốn lấy ListAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cur, new String[] { Phones.NAME, Phones.NUMBER }, new int[] { android.R.id.text1, android.R.id.text2 }); setListAdapter(adapter); } Bạn cần thay đổi một số thông tin trong AndroidMainfest.xml, bạn cần khai báo sử dụng đọc danh bạ điện thoại: <uses-permission android:name="android.permission.READ_CONTACTS" /> Source code và demo của chương trình này nằm ở DemoSeminar/Seminar_ContactList. Xây dựng và sử dụng một Content Provider: Mục địch việc xây dựng Content Provider: Bạn cần phải xây dựng một Content Provider nếu bạn muốn cung cấp một hoặc nhiều các tính năng sau: Bạn muốn cung cấp dữ liệu hoặc các tập tin từ ứng dụng của bạn vào ứng dụng khác. Bạn muốn cho phép người dùng sao chép dữ liệu từ ứng dụng của bạn vào các ứng dụng khác. Xây dựng Content Provider: Để xây dựng một Content Provider cho ứng dụng của mình bạn cần hiện thực và kế thừa từ một lớp có sẵn là contentProvider trong Android. Override tất cả các phương thức sau: onCreate(): khởi tạo một ứng dụng được bạn cung cấp. Hệ thống Android gọi phương thức này ngay sau khi nó tạo ra ứng dụng được bạn cung cấp. Chú ý rằng, ứng dụng được bạn cung cấp sẽ không được tạo ra cho đến khi có một đối tượng ContentResolver được truy cập. getType(): trả về định dạng MIME tương ứng với nội dung của một URI. Phương thức này sẽ được nói rõ hơn trong phần thực thi của Content Provider ở sau. insert(): chèn một dòng dữ liệu mới vào ứng dụng được bạn cung cấp. Trả về một định dạng URI cho dòng mới thêm vào. update(): cập nhật dòng dữ liệu hiện đang có trong ứng dụng được bạn cung cấp. Trả về số dòng được cập nhật. delete(): xóa dòng dữ liệu trong Provider của bạn. Trả về số dòng được xóa. query(): lấy dữ liệu từ Provider của bạn. Trả về dữ liệu dưới dạng một con trỏ Cursor. Giới thiệu về lớp UriMatcher: Lớp tiện ích để hỗ trợ trong việc kết hợp các URI trong Content Provider. Để giúp bạn lựa chọn các cách thức xử lí tốt đối với một mẫu URI, API cung cấp một số dịch vụ thuận tiện tại lớp UriMatcher, với một cây URI mẫu dưới dạng các số nguyên. Bạn có thể sử dụng các số nguyên này trong một câu lệnh mà bạn muốn xử lí với hành động là chuỗi URI được định danh. Để sử dụng lớp này, xây dựng một cây của các đối tượng UriMatcher, như ví dụ sau: private static final int PEOPLE = 1;     private static final int PEOPLE_ID = 2;     private static final int PEOPLE_PHONES = 3;     private static final int PEOPLE_PHONES_ID = 4;     private static final int PEOPLE_CONTACTMETHODS = 7;     private static final int PEOPLE_CONTACTMETHODS_ID = 8;     private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);     static     {         sURIMatcher.addURI("contacts", "people", PEOPLE);         sURIMatcher.addURI("contacts", "people/#", PEOPLE_ID);         sURIMatcher.addURI("contacts", "people/#/phones", _PHONES);         sURIMatcher.addURI("contacts", "people/#/phones/#", PEOPLE_PHONES_ID);         sURIMatcher.addURI("contacts", "people/#/contact_methods", PEOPLE_CONTACTMETHODS);         sURIMatcher.addURI("contacts", "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID);      } Một mô hình nội dung URI (UriMatcher) khớp với nội dung URI sử dụng để đăng kí phải sử dụng các kí tự đại diện sau: *: đại diện cho một chuỗi kí tự hợp lệ với độ dài bất kì. #: đại diện cho một chuỗi kí tự số với độ dài bất kì. Ví dụ: content://com.example.app.provider/*: đại diện cho nhiều chuỗi URI trong provider. content://com.example.app.provider/table2/*: đại diện cho các URI có chứa trong table2 content://com.example.app.provider/table3/#: đại diện cho các dòng của table3 Ví dụ về xây dựng một Content Provider: Bây giờ ta sẽ thiết kế một ứng dụng lấy với cơ sở dữ liệu chỉ là tạo ra 1 mã ID tự động và người dùng nhập tên vào trong EditText sau đó lưu xuống cơ sở dữ liệu SQLite. Dữ liệu của ứng dụng này sẽ được chia sẻ với bên ngoài bằng cách xây dựng một Content Provider. Đầu tiên, chúng ta tạo một lớp gọi là UserInfo kế thừa lớp ContentProvider như code sau: public class UserInfo extends ContentProvider { … } Trong lớp này ta tạo một số biến như tên của Content Provider, đường dẫn URI của Content Provider: //ten cua Content Provider. public static final String PROVIDER_NAME = "myandroid.net.User"; //duong dan URI cua Content Provider, cac ung dung khac se dung duong dan nay de public static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/users"); Sau đó chúng ta sẽ tạo uriMatcher để truy xuất Content Provider được dễ dàng: /cac chi so dung cho uriMatcher public static final int USERS = 1; public static final int USER_ID = 2; //khoi tao uriMatcher. public static final UriMatcher uriMatcher; static{ uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(PROVIDER_NAME, "users", USERS); uriMatcher.addURI(PROVIDER_NAME, "users/#", USER_ID); } Vì đây là một chương trình nhỏ và mô phỏng nên chúng ta không tao ra lớp DTO để thể hiện đối tượng nên mình sẽ tạo ra 2 biến để lấy và đưa giá trị và cơ sở dữ liệu: //hai bien de nhan gia tri id va name de dua vao co so du lieu public static final String sID = "ID"; public static final String sName = "Name"; Sau đó chúng tạo database như ở phần SQLite. Đến phần này mình xin khẳng định lại rằng Content Provider không phải là cách lưu trữ dữ liệu nên chúng ta phải sử dụng SQLite để lưu trữ dữ liệu. Mọi người có thể dùng các cách khác để lưu trữ, rất tiện lợi: //tao database private SQLiteDatabase gdb; private static final String DATABASE_NAME = "USERDEMO"; private static final String TABLE_NAME = "USER"; private static final int DATABASE_VERSION = 1; private static final String TABLE_CREATE = "CREATE TABLE [" + TABLE_NAME + "] (" +"[ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," + "[Name] TEXT NOT NULL)"; //su dung SQLtieOpenHelper de quan li viec luu du lieu private static class DatabaseHelper extends SQLiteOpenHelper { public DatabaseHelper(Context context) { super(context, DATABASE_NAME , null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(TABLE_CREATE); } @Override public void onUpgrade(SQLiteDatabase db, int version_old, int version_new) { db.execSQL("DROP TABLE IF EXISTS titles"); onCreate(db); } } Sau đó chúng ta override các phương thức có trong lớp Content Provider mà chúng ta cần. Đầu tiên là phương thức onCreate, trong phương thức này chúng ta khởi tạo database và trả về true nếu tạo thành công, ngược lại là false: @Override public boolean onCreate() { //lay context hien tai bang ham getContext Context context = this.getContext(); //tao database DatabaseHelper dbHelper = new DatabaseHelper(context); //mo database de doc va ghi gdb = dbHelper.getWritableDatabase(); return (gdb == null) ? false :true; } Trong ví dụ demo này mình chỉ override hàm insert, hàm này nhận hai tham số là: Uri uri: đường dân của Content Provider ContentValues values: giá trị cần đưa vào cơ sở dữ liệu, đối tượng này sẽ nhận các giá trị mà người dùng nhập vào @Override public Uri insert(Uri uri, ContentValues values) { //chen du lieu vao table cua database long rowID = gdb.insert(TABLE_NAME, "", values); //neu chen thanh cong thi thuc hien if(rowID > 0) { //tao mot dinh dang cho dong du lieu ban moi vua them vao Uri mUri = ContentUris.withAppendedId(CONTENT_URI, rowID); //khoi dong bang ContentResolver de doi tuong mUri tao thanh cong getContext().getContentResolver().notifyChange(mUri, null); return mUri; } throw new SQLException("Failed to insert new row into " + uri); } Cuối cùng là hàm query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) (). Hàm này: @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { //doi tuong dung de luu cac gia tri cua cau lenh truy van, gia cu moi khong de len gia tri cu SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder(); //set doi tuong SQLiteQueryBuilder len bang can lay du lieu sqlBuilder.setTables(TABLE_NAME); //su dung chuoi uriMatcher ma minh da tao, neu chuoi nay dan den vung du lieu cua table //thi lay du lieu ra khoi table if(uriMatcher.match(uri) == USER_ID) sqlBuilder.appendWhere(sID + "=" + uri.getPathSegments().get(1)); //sap xep du lieu tang dan theo id if(sortOrder == null || sortOrder == "") sortOrder = sID; //tao cursor bang du lieu ma minh da lay ra Cursor cur = sqlBuilder.query(gdb, projection, selection, selectionArgs, null, null, sortOrder); //khoi dong ContentResolver de doi tuong uri duoc hoat dong va du lieu duoc du ra cur.setNotificationUri(getContext().getContentResolver(), uri); return cur; } Tiếp đó chúng ta cần viết một số hàm trong lớp MainActivity. Hàm thêm dữ liệu vào database bằng cách nhận dữ liệu từ giao diện GUI: //them mot du lieu moi vao table private void onAdd() { //lay ten do nguoi dung nhap vao EditText String name = edtName.getEditableText().toString(); //day gia tri ten vao ContentValues ContentValues values = new ContentValues(); values.put(UserInfo.sName, name); //dua gia tri ContentValues vao co so du lieu thong qua duong dan Uri uriInsert = getContentResolver().insert(UserInfo.CONTENT_URI, values); //hien thong bao neu them du lieu thanh cong if(uriInsert != null) { Toast.makeText(this, "User's added", Toast.LENGTH_SHORT).show(); } } Hàm lấy toàn bộ dữ liệu trong cơ sở dữ liệu và hiển thị lên giao diện: //ham hien thi toan bo du lieu @SuppressWarnings("deprecation") private void onDisplay() { StringBuilder sb = new StringBuilder(); Uri uri = UserInfo.CONTENT_URI; //khoi tao cursor voi duong dan uri va sap xep tang dan theo id Cursor c = managedQuery(uri, null, null, null, "ID desc"); if(c.moveToFirst()){ do{ String userRecord = "ID = " + c.getString(c.getColumnIndex(UserInfo.sID)) + " Name = " + c.getString(c.getColumnIndex(UserInfo.sName)); sb.append(userRecord); sb.append("\n"); }while(c.moveToNext()); } else { sb.append("Chua co du lieu"); } ((TextView)this.findViewById(R.id.txtDisplay)).setText(sb.toString()); } Chúng ta cần thêm một số thông tin vào trong hàm AndroidMainfest.xml: <provider android:name = "UserInfo" android:authorities="myandroid.net.User" /> trong thẻ application. Tất cả source code và demo nằm trong thư mục DemoSeminar/Seminar_CreateContentProvider Sử dụng Content Provider mới tạo: Chúng ta đã tạo thành công một content Provider. Bây giờ chúng ta sẽ sử dụng Content Provider đã tạo bằng cách sử dụng uri. Ứng dung này có một button dùng để hiển thị toàn bộ dữ liệu có trong cơ sở dư liệu của ứng dụng mà ta đã tạo ở chương trên. Code: private void onDisplay() { //dung de chua toan bo du lieu lay ra tu co so du lieu cua ung dung lien ket StringBuilder sb = new StringBuilder(); //chuoi uri cua content provider chia se du lieu Uri uriGetListTitles = Uri.parse("content://myandroid.net.User/users"); //cursor dung de tro den du lieu con co so du lieu thong qua doi tuong uri Cursor c = managedQuery(uriGetListTitles, null, null, null, "ID desc"); if(c != null) { if(c.moveToFirst()){ do{ String bookRecord = "id = " + c.getString(c.getColumnIndex("ID")) + " - Full Name= " +c.getString(c.getColumnIndex("Name")); sb.append(bookRecord); sb.append("\n"); }while(c.moveToNext()); } } else { sb.append("Khong co du lieu"); } ((TextView)this.findViewById(R.id.txtDisplay)).setText(sb.toString()); } Tất cả source code và demo nằm trong thư mục DemoSeminar/Seminar_UseContentProvide

Các file đính kèm theo tài liệu này:

  • docxdatastorage_8378.docx