Các kỹ thuật lập trình nâng cao trên Android Các kỹ thuật lập trình nâng cao trên Android Các kỹ thuật lập trình nâng cao trên Android Các kỹ thuật lập trình nâng cao trên Android Các kỹ thuật lập trình nâng cao trên Android Các kỹ thuật lập trình nâng cao trên Android Các kỹ thuật lập trình nâng cao trên Android Các kỹ thuật lập trình nâng cao trên Android Các kỹ thuật lập trình nâng cao trên Android Các kỹ thuật lập trình nâng cao trên Android
Trang 12 Sử dụng SQLite thao tác với cơ sở dữ liệu quan hệ
Nội dung:
Việc lưu trữ dữ liệu trong Android bao gồm những cách phổ biến sau:
1 Lưu file trong file xml khi bạn cần làm chức năng setting cho máy, hay chỉ cần ghi những dữ liệu nhỏ (sử dụng SharedPreferences) Cơ chế “cấu hình chia
sẻ” (shared preferences) được dùng để lưu những dữ liệu nhỏ dưới dạng value (cặp tên khóa – giá trị khóa)
key-2 Đọc/ghi file trong bộ nhớ máy hay ngoài thẻ nhớ
3 Lưu trữ bằng database sử dụng cơ sở dữ liệu quan hệ cục bộ mà Android
hỗ trợ
Android cung cấp sẵn một cơ chế đơn giản giúp chúng ta lưu trữ nhanh các dữ liệu ngắn như cấu hình ứng dụng, tên đăng nhập, email,… và lấy lại dữ liệu đã ghi này trong các lần chạy ứng dụng tiếp theo
CÁC KỸ THUẬT NÂNG CAO TRÊN ANDROID
1 Cung cấp kỹ năng làm việc với các tệp dữ liệu trên bộ nhớ trong và trên bộ nhớ ngoài (thẻ nhớ)
Mục tiêu:
1 Làm việc với tệp tin trong Android
Có thể nói việc lưu trữ dữ liệu dữ liệu là một việc làm phổ biến trong Android
Vì vậy Android có khá nhiều cách cho phép chúng ta lưu trữ dữ liệu, với từng công việc khác nhau mà chúng ta lựa chọn sao cho phù hợp với yêu cầu Lưu trữ dữ liệu là tính năng quan trọng đối với những ứng dụng, giúp cho người dùng có thể dùng lại được những dữ liệu trước đó mà không cần nhập lại
2 Lưu trữ dữ liệu cố định với shared preferences
Trang 2Cách thức thuận tiện nhất là mô tả tập trung các cấu hình ta cần lưu lại trong một Activity (thường là màn hình “Settings” của ứng dụng) Android cung cấp sẵn
một loại Activity đặc biệt là PreferenceActivity giúp đơn hóa quá trình này
Preference là một phần quan trọng trong ứng dụng Android Nó rất quan trọng
vì giúp cho người dùng có những chọn lựa thay đổi và tùy chỉnh ứng dụng của họ theo những nhu cầu riêng biệt của cá nhân
Android Prefereces có thể được thiết lập qua hai cách Bạn có thể:
Tạo ra một file preferences.xml trong thư mục res/xml
Thiết lập các preferences thông qua code
Ví dụ 7.1 dưới đây minh họa cách sử dụng Activity này
Để tạo một chức năng Setting trong Android, chúng ta có thể dụng API Preference do Android cung cấp
Settings là 1 danh sách gồm nhiều Preference, với mỗi Preference là 1 thiết lập Ví dụ: Text message limit, Multimedia message limit, Mỗi Preference được xác định và lưu trữ giá trị bằng cặp thuộc tính (key - value); và được lưu trữ trong đối tượng SharedPreference
SharedPreference có thể lưu trữ các kiểu dữ liệu cơ bản như: boolean, float, int, long, string, string set và được lưu trữ trong:
/data/data/<package_name>/shared_prefs/<filename>.xml
Các loại Preference cơ bản gồm:
CheckBoxPreference: Hiển thị một item dạng checkbox Giá trị lưu trữ kiểu
boolean
EditTextPreference: hiển thị hộp thoại chứa EditText để người sử dụng input
dữ liệu vào từ bàn phím Dữ liệu lưu trữ kiểu String
ListPreference: hiển thị danh sách gồm nhiều item kiểu radio button (single
choice) Dữ liệu lưu trữ kiểu String
Trang 3 MultiSelectListPreference: hiển thị danh sách gồm nhiều item kiểu check
box (multi choice) Dữ liệu lưu trữ kiểu String Set
SwitchPreference: hiển thị toggle 2 trạng thái on/off Dữ liệu lưu trữ kiểu
boolean
RingtonePreference: cho phép người dùng chọn ringtone từ thiết bị Dữ liệu
lưu trữ kiểu String
Minh hoạ thiết lập Settings trong Android Các bước thực hiện tạo 1 Settings:
Bước 1: Định nghĩa Preference trong XML
Tạo file: filename.xml trong thư mục res/xml
Khai báo các Preference cần sử dụng
Trong đó có 3 thuộc tính quan trọng cần khai báo trong mỗi Preference:
android:key - Thuộc tính bắt buộc của một Preference và là giá trị kiểu String
duy nhất, được sử dụng để xác định một Preference
android:title - Tiêu đề của một Preference
android:defaultValue - Giá trị mặc định của một Preference
Trang 4 Bước 2: Tạo class MyActivity extent từ class PreferenceAcitivity
public class SettingsActivity extends PreferenceActivity
Bước 3: Lấy giá trị của một Preference (nếu cần)
Để có thể get được giá trị được của một Preference, chúng ta sử dụng đối tượng SharedPreference
Khai báo đối tượng SharedPreference và gọi phương thức
PreferenceManager.getDefaultSharedPreferences() để gắn giá trị cho đối tượng vừa được khai báo
Trang 5Với arg1: key của preference muốn get dữ liệu, key phải trùng với key được khai báo trong XML arg2: giá trị default nếu không tìm thấy được dữ liệu của preference
Bước 4: Lắng nghe sự kiện khi một Preference thay đổi giá trị
public class SettingsActivity extends PreferenceActivity
implements OnSharedPreferenceChangeListener { public static final String
KEY_PREF_SYNC_CONN="pref_syncConnectionType";
public void onSharedPreferenceChanged(SharedPreferences
sharedPreferences, String key) { if (key.equals(KEY_PREF_SYNC_CONN))
{ Preference connectionPref = findPreference(key);
Trong phương thức onSharedPreferenceChanged(), tham số
SharedPreference được dùng để get giá trị và tham số key được dùng để tìm kiếm một preference bằng cách gọi phương thức findPreference(int key)
Sau khi người dùng thay đổi giá trị của một Preference, chúng ta nên cập nhật
lại giá trị đó và hiển thị lên cho người dùng thấy sự thay đổi bằng thuộc tính sumary
Sử dụng phương thức setSummary() để thực hiện thay đổi
Trang 6Google đề nghị việc đăng kí và huỷ đăng kí lắng nghe sự kiện thay đổi giá trị của preference được thực hiện trong phương thức onResume() và onPause()
Để sử dụng được PreferenceActivity, trước hết ta mô tả các thông tin ta cần
lưu lại trong một tài liệu xml trong thư mục “res/xml”, trong ví dụ này, ta tạo file
“res/xml/myapppreferences.xml” với nội dung như sau:
Trang 7<PreferenceScreen android:title="Second Preference Screen"
android:summary="Click here to go to the 2rd Preference Screen"
Trang 8Sau khi bạn thay đổi giá trị của các mục cấu hình trong Activity này, hệ thống
sẽ tự động lưu lại giá trị của chúng để có thể sử dụng được trong các lần tiếp theo
Việc lưu trữ dữ liệu này là trong suốt với người dùng, tuy nhiên với máy ảo Android ta có thể xem được cụ thể các giá trị này Trên thực tế chúng được lưu trong
1 file xml nằm trên bộ nhớ trong, trong vùng nhớ chỉ có thể truy cập được bởi ứng
dụng tạo ra nó, ở đây là tệp appPreferences.xml (thư mục /data/data/{package-name} /shared_prefs/appPreferences.xml):
Trang 9Nội dung file này có dạng như sau:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="editTextPref">HUMG - Software engineer</string>
<string name="secondEditTextPref">HUMG - 2nd screen text</string>
<string
name="ringtonePref">content://settings/system/ringtone</string>
<boolean name="checkboxPref" value="true" />
</map>
Để lấy giá trị của các cấu hình này trong code, ta làm như sau:
SharedPreferences appPrefs = getSharedPreferences("appPreferences",
Trang 10Trong trường hợp bạn cần lưu lại dữ liệu tương đối phức tạp hơn (khó có thể
lưu lại dạng key-value trong shared preference), ta có thể dùng hệ thống file Trong
Android, để làm việc (nhập/xuất) với file, ta có thể dụng các lớp của gói java.io Trong phần này ta sẽ xem cách làm việc với file trong bộ nhớ trong lẫn bộ nhớ ngoài
Thư mục lưu trữ: /data/data/<package_name>/<files>/<fileName>
Để tạo file và ghi dữ liệu cho file vào trong bộ nhớ trong, thực hiện các bước sau:
Bước 1: Tạo đối tượng FileOutputStream và lấy giá trị bằng phương thức openFileOutput(fileName, Mode) với tên file và chế độ truy cập file
Bước 2: Ghi dữ liệu bằng phương thức write() Lưu ý: phương thức write() nhận tham số đầu vào là một mảng byte[] vì thế cần phải chuyển dữ liệu từ
3 Làm việc với file dữ liệu văn bản
3.1 Làm việc với file trong bộ nhớ trong
Chúng ta có thể thực hiện lưu trữ file vào trong bộ nhớ trong của thiết bị, mặc định đây là những file private của ứng dụng và các ứng dụng khác không được phép truy cập vào (kể cả cả người dùng) Khi ứng dụng được uninstall, những file này cũng
sẽ bị xoá
Trang 11văn bản (kiểu String), hình ảnh (kiểu Bitmap), sang mảng byte[] trước khi gọi phương thức write()
Bước 3: Đóng stream bằng phương thức close()
Các mode được cung cấp:
MODE_PRIVATE: mode mặc định, với chế độ này, file sẽ được tạo (nếu chưa tồn tại) hoặc ghi đè lên file đã được tạo Bên cạnh đó, chế độ này giữ cho file
là private đối với ứng dụng
MODE_APPEND: với chế độ này, file sẽ được tạo (nếu chưa tồn tại) hoặc ghi tiếp vào file đã được tạo
MODE_WORLD_WRITEABLE
a) Đọc file được lưu trong bộ nhớ trong
Để đọc file được lưu trữ trong bộ nhớ trong, thực hiện các bước sau:
Bước 1: Tạo đối tượng FileInputStream và lấy giá trị bằng phương thức
openFileInput(fileName)
Bước 2: Đọc dữ liệu bằng phương thức read()
Bước 3: Đóng stream bằng phương thức close()
Chú ý, phương thức read hỗ trợ các kiểu như sau:
read(): đọc các giá trị byte cho đến khi gặp giá trị -1 thì dừng Sau mỗi lần đọc
sẽ trả về 1 giá trị kiểu int có miền giá trị từ [0-255] được convert từ byte Sử dụng: Dùng trong trường hợp không xác định được kích thước của file Hạn chế: phải tốn mảng int[] để lưu trữ giá trị và phải chuyển về mảng byte[] để lấy dữ liệu ra
read(byte[]): đọc toàn bộ dữ liệu và đưa vào mảng byte[] Được sử dụng khi xác định được kích thước của file để khởi tạo mảng byte[] trước khi được dùng
Trang 12Ví dụ 7.2: Ta sẽ tạo một Activity có một ô nhập văn bản (EditText) và 2 nút
bấm cho phép ghi và đọc văn bản này vào file Layout của Activity này như sau:
Trang 13Mã nguồn của Activity với 2 hàm đọc (onClickLoad) và ghi (onClickSave)
vào file như sau:
static final int READ_BLOCK_SIZE = 100;
/** Called when the activity is first created */
Trang 14{ FileOutputStream fOut = openFileOutput("textfile.txt",
MODE_PRIVATE); OutputStreamWriter osw = new
{ FileInputStream fIn = openFileInput("textfile.txt");
InputStreamReader isr = new InputStreamReader(fIn);
char[] inputBuffer = new char[READ_BLOCK_SIZE];
String s = "";
int charRead;
while ((charRead = isr.read(inputBuffer))>0)
{ // -convert the chars to a String -
String readString=String.copyValueOf(inputBuffer,0, charRead);
Trang 15catch (IOException ioe)
{
ioe.printStackTrace();
}
}
Trong đoạn mã trên, ta thấy việc đọc ghi vào file tương đối đơn giản và quen
thuộc, để ghi dữ liệu vào file, ta tạo một đối tượng OutputStreamWriter trên luồng xuất FileOutputStream và tiến hành ghi vào qua phương thức write Sau đó gọi flush
để đẩy hết dữ liệu trong bộ đệm vào file và đóng luồng lại:
FileOutputStream fOut = openFileOutput("textfile.txt", MODE_PRIVATE);
OutputStreamWriter osw = new OutputStreamWriter(fOut);
// -write the string to the file -
osw.write(str);
osw.flush();
osw.close();
Để đọc nội dung file này, ta cũng thao tác tương tự, tạo đối tượng
InputStreamReader từ luồng nhập liệu (FileInputStream) và tiến hành đọc dữ liệu
Trang 16bằng phương thức read() Mỗi lần đọc sẽ đọc READ_BLOCK_SIZE byte và lưu vào
bộ đệm (mảng byte), nội dung này sẽ được chuyển thành string và nối thêm vào biến
s, quá trình được lặp lại cho đến khi hết nội dung của file:
FileInputStream fIn = openFileInput("textfile.txt");
InputStreamReader isr = new InputStreamReader(fIn);
char[] inputBuffer = new char[READ_BLOCK_SIZE];
Một câu hỏi đặt ra là file "textfile.txt" ở trên được tạo ra ở đâu trong cây thư
mục Câu trả lời là nó được tạo ra trong bộ nhớ trong của thiết bị, trong thư mục dành
riêng cho ứng dụng (/data/data/{package-name}/files)
Chạy ứng dụng, nhập nội dung cho ô nhập liệu và bấm Save, ta sẽ thấy nội dung văn bản này được ghi vào file trong bộ nhớ trong
Kết quả:
Trang 17Kéo file này về máy tính để xem nội dung file, ta sẽ thấy nội dung văn bản ta nhập vào trước đó:
Dữ liệu được lưu trữ tại bộ nhớ ngoài có thể truy cập được từ các ứng dụng, người sử dụng và trạng thái của bộ nhớ ngoài không chắc là khả dụng - khi người dùng unmount, toàn bộ dữ liệu được lưu trên bộ nhớ ngoài sẽ không thể truy cập được
Đọc và ghi dữ liệu tại bộ nhớ ngoài: tương tự như đọc ghi tại bộ nhớ trong, chỉ
lưu ý vài điều như sau:
3.2 Làm việc với file trong bộ nhớ ngoài
External Storage được hiểu là thẻ nhớ gắn ngoài SD card hoặc một phân vùng trong bộ nhớ thiết bị đối với các thiết bị không đề nghị sử dụng SD card
Bộ nhớ ngoài là nơi lưu trữ các dữ liệu có tính chất dùng chung như: hình ảnh,
âm thanh, video
Trang 18 Đối với bộ nhớ trong, file được lưu trữ vào thư mục chứa cài đặt của ứng dụng,
vì thế chỉ cần xác định được tên file là có thể truy xuất được nội dung file Đối với bộ nhớ ngoài, cần xác định đường dẫn đến file để có thể ghi và đọc file
Khi tạo đối tượng FileInputStream để đọc hoặc FileOutputStream để ghi, đối với bộ nhớ trong sử dụng phương thức openFileInput(fileName) hoặc phương thức openFileOutput(fileName, mode); đối với sử dụng bộ nhớ ngoài, cần sử dụng toán tử new để tạo đối tượng FileInputStream hoặc đối tượng
FileOutputStream
File trong bộ nhớ trong chỉ được truy cập bởi ứng dụng tạo ra nó Ngoài ra dung lượng lưu trữ của bộ nhớ trong thường hạn chế hơn bộ nhớ ngoài (SDCard) Vì vậy trong trường hợp ta muốn chia sẻ thông tin lưu trữ với các ứng dụng khác, ta nên
sử dụng bộ nhớ ngoài Làm việc với file trong bộ nhớ ngoài hoàn toàn tương tự với file trong bộ nhớ trong, chỉ khác phần lấy ra FileInputStream và FileOutputStream:
Thay vì dùng:
FileOutputStream fOut = openFileOutput("textfile.txt", MODE_PRIVATE);
Ta dùng:
File sdCard = Environment.getExternalStorageDirectory();
File directory = new File(sdCard.getAbsolutePath() + "/MyFiles");
directory.mkdirs();
File file = new File(directory, "textfile.txt");
FileOutputStream fOut = new FileOutputStream(file);
Và thay vì:
FileInputStream fIn = openFileInput("textfile.txt");
Ta dùng:
File sdCard = Environment.getExternalStorageDirectory();
File directory = new File (sdCard.getAbsolutePath() + "/MyFiles");
Trang 19File file = new File(directory, "textfile.txt");
FileInputStream fIn = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fIn);
Mọi thao tác ứng xử vẫn như trường hợp trước, chỉ khác bị trí lưu trữ file trong cây thư mục:
Mỗi ứng dụng đều sử dụng dữ liệu, dữ liệu có thể rất đơn giản hay đôi khi là
cả 1 cấu trúc Trong Android thì hệ cơ sở dữ liệu được sử dụng là SQLite Database, đây là hệ thống mã nguồn mở được sử dụng rộng rãi trong các ứng dụng
Ví dụ như Mozilla Firefox sử dụng SQLite để lưu trữ các dữ liệu về cấu hình, iPhone cũng sử dụng cơ sở dữ liệu là SQLite,
Trong Android, cơ sở dữ liệu mà bạn tạo cho 1 ứng dụng thì chỉ ứng dụng đó
có quyền truy cập và sử dụng, còn các ứng dụng khác thì không được phép
Trong phần trước ta đã tìm hiểu cách lưu dữ liệu vào file và vào shared preferences Tuy nhiên với loại dữ liệu quan hệ thì sử dụng cơ sở dữ liệu quan hệ sẽ thuận tiện hơn rất nhiều Ví dụ ta cần lưu trữ kết quả kiểm tra của các sinh viên trong trường học, dùng cơ sở dữ liệu sẽ cho phép chúng ta truy vấn kết quả của tập sinh
4 Làm việc với cơ sở dữ liệu SQLite
4.1 Giới thiệu về SQLite database