2. 2
Nội dung bài học
●
SQLite & Android.
●
Content Provider.
●
System Preferences (*)
3. 3
SQLite & Android
●
Giới thiệu về SQLite.
●
SQLite trong Android.
●
Android SQLite API.
●
Ví dụ.
●
Truy xuất CSDL qua shell1.
1
Xem ở bài 6:”Multi theme, adb tool and JUnit”
4. 4
Giới thiệu về SQLite
●
SQLite là một thư viện hiện thực SQL Database Engine với các
đặc điểm sau:
●
Selft-contained → Phụ thuộc rất rất ít thư viện khác hay OS.
●
Serverless → Không cần server.
●
Zero-configuration → Không cần cài đặt, cấu hình.
●
Transactional → ACID (Atomic, Consistent, Isolated, Durable)
●
Mã nguồn của SQLite được công bố ở “public domain”.
●
Hỗ trợ các kiểu dữ liệu TEXT, INTEGER, REAL
●
●
●
Các kiểu dữ liệu khác phải chuyển sang 3 kiểu dữ liệu trên trước khi ghi vào cơ
sở dữ liệu.
SQLite không kiểm tra kiểu dữ liệu khi ghi.
SQLite hỗ trợ ANSI SQL92.
Tham khảo thêm thông tin tại: http://www.sqlite.org
5. 5
SQLite & Android
●
●
●
●
SQLite được phân phối cùng với Android. Để sử dụng
SQLite chúng ta không cần cài đặt hay cấu hình thêm bất cứ
điều gì.
Sử dụng câu lệnh DDL để tạo cơ sở dữ liệu trong mã nguồn.
Truy xuất cơ sở dữ liệu SQLite tức là truy xuất file. Để
tránh block UI thread cần sử dụng các kỹ thuật
“Background processing”.
Mặc định tập tin cơ sở dữ liệu tạo ra tại:
DATA/data/APP_NAME/databases/FILENAME
●
DATA là đường dẫn Environment.getDataDirectory()
●
APP_NAME tên của ứng dụng.
●
FILENAME tên của cơ sở dữ liệu, chỉ định trong khi tạo cơ
sở dữ liệu.
6. 6
Android SQLite API
●
Package:
●
●
●
android.database → Các interface/class làm việc với
database.
android.database.sqlite → Các interface/class làm việc
với SQLite.
Class:
●
SQLiteOpenHelper → Tạo/Nâng cấp cơ sở dữ liệu.
●
SQLiteDatabase → Base class để làm việc với CSDL.
●
SQLiteQueryBuilder → Tạo câu truy vấn SQL.
●
Cursor → Chứa kết quả của câu truy vấn SQL.
7. 7
SQLiteOpenHelper
●
Tạo lớp kế thừa từ SQLiteOpenHelper để tạo hay
nâng cấp CSDL. Các điểm cần quan tâm ở lớp kế
thừa:
●
●
●
●
●
Phương thức khởi tạo: Cần gọi super() và truyền hai tham số
bắt buộc là tên của CSDL và phiên bản hiện tại.
Override phương thức onCreate.Phương thức này được gọi
khi CSDL chưa tồn tại.
Override phương thức onUpgrade.Phương thức này được gọi
khi phiên bản CSDL được tăng lên.
Cả hai phương thức onCreate và onUpgrade đều truyền vào đối
tượng SQLiteDatabase của CSDL hiện tại. Chúng ta dùng nó và
các câu lệnh DDL để tạo/thay đổi schema của CSDL.
Bảng trong CSDL phải có khoá chính tên _id.
8. 8
SQLiteDatabase
●
●
●
SQLiteDatabase là base class cho phép chúng ta làm việc với
CSDL thông qua các phương thức insert, update, delete,
executeSQL.
Khi insert/update dữ liệu, chúng ta có thể dùng ContentValues
class để định nghĩa dữ liệu theo dạng key/value. Trong đó “key”
là tên của cột, “value” là giá trị của cột đó.
SQLiteQueryBuilder class giúp ta xây dựng các query() hay
rawQuery().
Cursor cursor = getReadableDatabase().
rawQuery("select * from employee where _id = ?", new String[] { id });
9. 9
Cursor
●
●
Kết quả trả về từ câu lệnh truy vấn là một Cursor. Cursor trỏ đến
một dòng trong kết quả truy vấn. Phương pháp lưu trữ kết quả
trả về sử dụng Cursor giúp Android tiết kiệm vùng nhớ vì nó
không cần phải load tất cả dữ liệu lên bộ nhớ.
Một số phương thức thường dùng trong lớp Cursor:
●
●
●
●
getCount() → số lượng hàng trong kết quả truy vấn.
moveToFirst(), moveToNext() → di chuyển con trỏ đến hàng
đầu tiên hay hàng kế tiếp.
isAfterLast() → kiểm tra xem đã đến cuối kết quả chưa.
Các phương thức get như getLong(colidx), getString(colidx)
→ lấy giá trị của cột tương ứng colidx tại hàng hiện tại.
●
getColumnIndexOrThrow(String) → lấy colidx từ tên cột.
●
close() → close Cursor.
10. 10
Ví dụ
●
Viết chương trình có giao diện như trong hình
(sử dụng CSDL để lưu trữ dữ liệu)
●
●
Nếu nút “Thêm” được nhấn: Chọn 1 tên từ danh
sách tên đã định trước thêm vào đầu danh sách.
Nếu nút “Xoá” được nhấn: Xoá tên đang ở đầu danh
sách.
11. 11
Ví dụ
●
Tạo lớp SampleDBOpenHelper:
//Bỏ qua phần package & import
public class SampleDBOpenHelper extends SQLiteOpenHelper {
public static final String TABLE_EMPLOYEE_INFO = "employee_info";
public static final String COLUMN_EMPLOYEE_ID = "_id";
public static final String COLUMN_EMPLOYEE_NAME = "employee_name";
private static final String DATABASE_NAME = "employee.db";
private static final int DATABASE_VERSION = 1;
//Câu truy vấn tạo bảng EMPLOYEE_INFO
private static final String DATABASE_CREATE = "create table " +
TABLE_EMPLOYEE_INFO + "(" + COLUMN_EMPLOYEE_ID +
" integer primary key autoincrement, " + COLUMN_EMPLOYEE_NAME +
" text not null);";
public SampleDBOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(DATABASE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(SampleDBOpenHelper.class.getName(),
"Upgrading database from version " + oldVersion + " to " +newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_EMPLOYEE_INFO);
onCreate(db);
}
}
12. 12
Ví dụ
Tạo lớp model cho bảng employee_info:
●
//Bỏ qua phần package
public class EmployeeInfo {
private long employee_id;
private String employee_name;
//Getter & setter sinh tự động bằng Eclipse
public long getEmployee_id() {
return employee_id;
}
public void setEmployee_id(long employee_id) {
this.employee_id = employee_id;
}
public String getEmployee_name() {
return employee_name;
}
public void setEmployee_name(String employee_name) {
this.employee_name = employee_name;
}
// Sử dụng trong ArrayAdapter để trình bày lên ListView
@Override
public String toString() {
return employee_name;
}
}
13. 13
Ví dụ
●
Hiện thực DAO (Data Access Object) lớp:
//Bỏ qua package & import
public class EmployeeDataSource {
private SQLiteDatabase db;
private SampleDBOpenHelper dbOpenHelper;
private String[] allColumns = {
SampleDBOpenHelper.COLUMN_EMPLOYEE_ID, SampleDBOpenHelper.COLUMN_EMPLOYEE_NAME
};
public EmployeeDataSource(Context context) {
dbOpenHelper = new SampleDBOpenHelper(context);
}
public void open() throws SQLException {
db = dbOpenHelper.getWritableDatabase();
}
public void close() {
dbOpenHelper.close();
}
public EmployeeInfo createEmployee(String name) {
ContentValues values = new ContentValues();
values.put(SampleDBOpenHelper.COLUMN_EMPLOYEE_NAME, name);
long insertId = db.insert(SampleDBOpenHelper.TABLE_EMPLOYEE_INFO, null, values);
Cursor cursor = db.query(SampleDBOpenHelper.TABLE_EMPLOYEE_INFO,allColumns,
SampleDBOpenHelper.COLUMN_EMPLOYEE_ID + " = " + insertId, null, null, null, null);
cursor.moveToFirst();
EmployeeInfo newEmployee = cursorToEmployee(cursor);
cursor.close();
return newEmployee;
}
14. 14
Ví dụ
●
Hiện thực DAO lớp:
public void deleteEmployee(EmployeeInfo employee) {
long id = employee.getEmployee_id();
Log.d(this.getClass().getName(), "Employee deleted with id: " + id);
db.delete(SampleDBOpenHelper.TABLE_EMPLOYEE_INFO,
SampleDBOpenHelper.COLUMN_EMPLOYEE_ID + " = " + id, null);
}
public List<EmployeeInfo> getAllEmployees() {
List<EmployeeInfo> employeeList = new ArrayList<EmployeeInfo>();
Cursor cursor = db.query(SampleDBOpenHelper.TABLE_EMPLOYEE_INFO,
allColumns, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
EmployeeInfo employee = cursorToEmployee(cursor);
employeeList.add(employee);
cursor.moveToNext();
}
//Nhớ close cursor!!!
cursor.close();
return employeeList;
}
private EmployeeInfo cursorToEmployee(Cursor cursor) {
EmployeeInfo employee = new EmployeeInfo();
employee.setEmployee_id(cursor.getLong(0));
employee.setEmployee_name(cursor.getString(1));
return employee;
}
}
16. 16
Ví dụ
●
MainActivity:
//Bỏ qua import & package
public class MainActivity extends ListActivity {
private EmployeeDataSource datasource;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_main);
datasource = new EmployeeDataSource(this);
datasource.open();
List<EmployeeInfo> values = datasource.getAllEmployees();
// Sử dụng SimpleCursorAdapter
ArrayAdapter<EmployeeInfo> adapter = new ArrayAdapter<EmployeeInfo>(this,
android.R.layout.simple_list_item_1, values);
setListAdapter(adapter);
}
@Override
protected void onResume() {
datasource.open();
super.onResume();
}
@Override
protected void onPause() {
datasource.close();
super.onPause();
}
}
17. 17
Ví dụ
●
MainActivity:
public void onClick(View view) {
@SuppressWarnings("unchecked")
ArrayAdapter<EmployeeInfo> adapter = (ArrayAdapter<EmployeeInfo>) getListAdapter();
EmployeeInfo employee = null;
switch (view.getId()) {
case R.id.add:
String[] employees = new String[] { "Phước", "An", "Nguyên", "Sơn" };
int nextInt = new Random().nextInt(4);
// Save the new comment to the database
employee = datasource.createEmployee(employees[nextInt]);
adapter.add(employee);
break;
case R.id.delete:
if (getListAdapter().getCount() > 0) {
employee = (EmployeeInfo) getListAdapter().getItem(0);
datasource.deleteEmployee(employee);
adapter.remove(employee);
}
break;
}
adapter.notifyDataSetChanged();
}
18. 18
Content Provider
●
Giới thiệu về Content Provider.
●
Hiện thực Content Provider.
●
Contract Class.
●
Sử dụng Content Provider.
●
Content Provider & Loader1.
1
Xem ở bài 2:”Background processing”
19. 19
Giới thiệu Content Provider
●
●
●
CSDL SQLite chỉ dùng trong ứng dụng. Để chia sẻ dữ liệu này
có các ứng dụng khác cần dùng Content Provider.
Content Provider là một cơ chế cho phép truy xuất (truy vấn,
thêm, sửa, xoá) dữ liệu (tập tin, csdl) của một ứng dụng từ một
ứng dụng khác.
Ví dụ:
●
Truy xuất lịch sử các cuộc gọi.
●
Truy xuất bookmark của web browser.
●
Truy xuất sổ địa chỉ.
●
Truy xuất vào lịch.
20. 20
Giới thiệu Content Provider
STT
Tên
Mô tả
1
query
Truy vấn dữ liệu, trả kết quả về
qua Cursor.
2
insert
Thêm dữ liệu
3
update
Cập nhật dữ liệu
4
delete
Xoá dữ liệu
Application
Content Provider
CSDL
Query
Insert
Update
Delete
External App
21. 21
Hiện thực Content Provider
●
Tạo lớp kế thừa lớp ContentProvider.
●
Hiện thực các phương thức trừu tượng.
●
Đăng ký provider vào AndroidManifest.
22. 22
Hiện thực Content Provider
●
Tạo lớp kế thừa lớp ContentProvider:
●
Trong lớp ContentProvider có 6 phương thức trừa tượng cần
được hiện thực:
Tên
Giá trị trả về
Mô tả
onCreate
boolean
●
Được gọi khi khởi động provider.
●Nếu quá trình khởi tạo thành công trả về true,
ngược lại trả về false.
getType
String
●
query
Cursor
●
insert
int
●
update
int
●
delete
int
●
Trả về MIME của URL được cung cấp.
Truy vấn dữ liệu.
●Kết quả trả về là một Cursor.
Thêm dữ liệu
●Trả về số lượng hàng dữ liệu thêm vào.
Thay đổi dữ liệu.
●Trả về số lượng hàng thay đổi.
Xoá dữ liệu.
●Trả về số lượng hàng bị xoá.
23. 23
Hiện thực Content Provider
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
public class SampleProvider extends ContentProvider {
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
24. 24
Hiện thực Content Provider
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
return 0;
}
}
25. 25
Hiện thực Content Provider
●
Hiện thực các phương thức trừu tượng nếu cần thiết.
●
●
●
Hiện thực phương thức onCreate: Tạo đối tượng của lớp con
của lớp SQLiteOpenHelper và sử dụng phương thức
getContext để lấy Context hiện tại. Lưu đối tượng này vào
biến thành viên của lớp.
Hiện thức 4 phương thức thao tác trên CSDL thì sử dụng đối
tượng đã lưu ở trên để lấy đối tượng SQLiteDatabase. Sau đó
sử dụng đối tượng SQLiteDatabase để thao tác trên CSDL.
Hiện thực phương thức getType: Bình thường trả về null.
Trong trường hợp phân chia ra nhiều thì nên trả về MIME
cho từng trường hợp.
26. 26
Hiện thực Content Provider
・・・
private SampleDBOpenHelper dbOpenHelper;
private SQLiteDatabase db;
@Override
public boolean onCreate() {
dbOpenHelper = new SampleDBOpenHelper(getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
db = dbOpenHelper.getReadableDatabase();
return db.query(SampleDBOpenHelper.TABLE_EMPLOYEE_INFO,
projection, selection, selectionArgs, null, null, sortOrder);
}
・・・
27. 27
Bài tập 07
●
Hiện thực chức năng cho xoá một dòng trong
bảng EMPLOYEE_INFO bằng ContentProvider
trong phần ví dụ.
28. 28
Hiện thực Content Provider
●
Đăng ký provider vào AndroidManifest.xml:
1.Doubclick vào AndroidManifest, chọn “Application”
tab.
2.Nhấn vào nút “Add” ở “Application Nodes”
2
1
29. 29
Hiện thực Content Provider
●
Đăng ký provider vào AndroidManifest.xml:
3.Chọn “Provider” và nhấn nút “OK”.
Chọn lại chọn lựa 1 nếu màn hình bên trái hiện ra
3
30. 30
Hiện thực Content Provider
●
Đăng ký provider vào AndroidManifest.xml:
4.Nhập vào tên của provider ở ô “Name”. Có thể dùng
nút “Browse” để tìm provider.
4
31. 31
Hiện thực Content Provider
●
Đăng ký provider vào AndroidManifest.xml:
5.Nhập một chuỗi vào “Authorities Tag”, thường dùng
package name.
5
32. 32
Hiện thực Content Provider
●
Đăng ký provider vào AndroidManifest.xml:
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
...
<provider android:authorities="com.example.samplecontentprovider"
android:name="SampleProvider"></provider>
</application>
33. 33
Contract Class
●
●
●
Để cung cấp thông tin về provider như các URI, tên của các cột,
intent action, ... người ta sử dụng các lớp đặc biệt gọi là Contract
Class.
Các provider được cung cấp sẵn trong Android thường cung cấp
kèm theo Contract class trong package android.provider.
Ví dụ:
●
●
UserDictionary Provider cung cấp Contract class
UserDictionary.Words.
Contact Provider cung cấp Contract class ContactsContract.
34. 34
Sử dụng Content Provider
●
Để truy xuất dữ liệu cung cấp bởi provider chúng ta tiến hành
các bước sau đây:
1. Xác định Uri của provider.
2. Sử dụng phương thức Context#getContentResolver để truy
xuất đối tượng ContentResolver.
3. Sử dụng Uri và các phương thức cung cấp bởi
ContentResolver để truy xuất đến provider.
Tham khảo thêm lớp UriMatcher để theo tác với Uri.
35. 35
Sử dụng Content Provider
●
Định dạng của chuỗi Uri:
content://<Authorities>/<Phần tuỳ chọn>
●
“content://” → scheme: xác định đây là provider.
●
Authorities → Phân biệt các provider với nhau.
●
Phần tuỳ chọn: Xác định nội dung dữ liệu cần cung cấp.
36. 36
Ví dụ
Uri uri = Uri.parse("content://com.example.samplecontentprovider");
Cursor cursor = getContentResolver().query(uri,null,null,null,null);
List<EmployeeInfo> values = new ArrayList<EmployeeInfo>();
cursor.moveToFirst();
EmployeeInfo employee = null;
while (!cursor.isAfterLast()) {
employee = new EmployeeInfo();
employee.setEmployee_id(cursor.getLong(0));
employee.setEmployee_name(cursor.getString(1));
values.add(employee);
cursor.moveToNext();
}
//Nhớ close cursor!!!
cursor.close();