Drupal Consultant
Started my career as a drupal8 developer in EM Solutions . I love learning Web technologies like HTML, CSS, PHP, Jquery Ajax and Drupal backend . Currently working as a drupal backend developer.
Trong phần này, chúng ta sẽ tạo một ứng dụng mẫu (xem hình 9a, 9b) để hiển thị tất cả các địa chỉ liên lạc trong danh bạ điện thoại bằng cách sử dụng widget listView
. Mục đích của ví dụ này là để giới thiệu không chỉ là việc sử dụng widget listView
mà còn cho thấy dữ liệu điện thoại có thể được tìm nạp như thế nào khi sử dụng các lớp ContentProvider và ContentResolver. Hãy chú ý đến các tệp XML của giao diện người dùng vì có hai cách bố trí giao diện người dùng: một để xác định cách widget listView
sẽ hiển thị danh sách khít với giao với giao diện người dùng chính và cái kia để xác định cách hiển thị từng phần tử của danh sách đó. Một điểm quan trọng là thiết lập các quyền hạn cho các ứng dụng có thể đọc dữ liệu điện thoại. Ví dụ này là bước đầu tiên để hiểu được cách có thể kết hợp các ý định (intent) và các bộ lọc ý định trong một ứng dụng. Mặc dù các intent nằm ngoài phạm vi của bài viết này, nhưng độc giả cũng nên lưu ý rằng để chuyển ứng dụng của ví dụ này thành một ứng dụng danh bạ điện thoại trong thế giới thực, chỉ cần triển khai thực hiện các thao tác nhấn vào các mục của danh sách và tạo một ý định (intent) cuộc gọi và bộ lọc ý định để bắt đầu một cuộc gọi đến địa chỉ liên lạc được chọn.
Trong ví dụ này, các địa chỉ liên lạc sẽ được hiển thị theo mẫu thẳng theo chiều dọc và địa chỉ liên lạc được chọn sẽ xuất hiện ở đầu danh sách với một phông chữ in nghiêng lớn và một nền màu xanh dương. Chúng ta cũng có một hộp kiểm tra ở phía dưới cùng bên trái của màn hình, mà khi được đánh dấu chọn, sẽ hiển thị chỉ các địa chỉ liên lạc được đánh dấu sao (hoặc các địa chỉ liên lạc ưa thích). Tiêu đề của ứng dụng trong trường hợp này là "Contact Manager (Trình quản lý các địa chỉ liên lạc). Ở đây chúng ta sử dụng ba loại widget: textView
, listView
và checkBox
. Chúng ta sử dụng widget textView
để hiển thị địa chỉ liên lạc hiện đang được chọn. Bạn có thể đoán ngay rằng widget listView
là một danh sách các widget textView
. Widget listView
sử dụng các mẫu thiết kế của bộ tiếp hợp để kết nối dữ liệu (trong trường hợp này là các địa chỉ liên lạc) và một khung nhìn dữ liệu (trong trường hợp này là một textView
cho listView
này. Mọi thao tác nhấn trên listView
có thể được bắt giữ lại bằng cách thực hiện phương thức AdapterView.OnItemClickListener()
.
Trước khi tiếp tục, chúng ta nên có một số các địa chỉ liên lạc được lưu trong phần các địa chỉ liên lạc của trình mô phỏng thiết bị của Android (AVD). Điều này có thể được thực hiện bằng cách nhấn vào Contacts (Các địa chỉ liên lạc) trên màn hình chủ của AVD, sau đó nhấn vào Menu để có tùy chọn Add Contacts (Thêm các địa chỉ liên lạc). Phần Favorites (Các địa chỉ liên lạc ưa thích) cho biết cách đánh dấu một địa chỉ liên lạc như là ưa thích/được đánh dấu sao.
Hình 9a. Ứng dụng các địa chỉ liên lạc hiển thị tất cả các địa chỉ liên lạc trong một widget listView
Hình 9b. Ứng dụng các địa chỉ liên lạc hiển thị tất cả các địa chỉ liên lạc được đánh dấu sao trong một widget listView khi đánh dấu chọn vào hộp kiểm tra hiển thị các địa chỉ liên lạc có đánh dấu sao
Bây giờ chúng ta sẽ định nghĩa một vài chuỗi.
Liệt kê 5. Các chuỗi được định nghĩa trong tệp strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, Manager!</string> <string name="app_name">Contact Manager</string> <string name="selectedEntry" /> <color name="White">#FFFFFF</color> <color name="Black">#000000</color> <color name="Blue">#0000FF</color> <string name="showStarred">Show starred contacts only</string> </resources>
Tệp main.xml
Chúng ta hãy định nghĩa cách bố trí chính cho ứng dụng của mình. Widget listView
sẽ cung cấp danh sách tất cả các địa chỉ liên lạc trong danh bạ điện thoại. listView
hiển thị từng mục bên trong một widget textView
, mà chúng ta sẽ định nghĩa tiếp sau.
Liệt kê 6. Tệp main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/
apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:id="@+id/selectedContact" android:padding="10dp" android:textSize="20sp" android:textStyle="italic" android:typeface="serif" android:background="@color/Blue" android:textColor="@color/White" android:text="@string/selectedEntry"/> <ListView android:id="@+id/contactsListView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1"> </ListView> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/showStarred" android:text="@string/showStarred"/> </LinearLayout>
Lưu ý rằng việc gán cho thuộc tính layout_weight giá trị bằng 1 trong listView
bảo đảm chắc chắn rằng danh sách phủ hết vùng màn hình càng lớn càng tốt cho đến khi một widget mới được định nghĩa.
Tệp contactItem.xml
Bên cạnh bố trí chính, chúng ta cần phải xác định một cách bố trí khác ở đây. Việc này là để thể hiện từng phần tử trong listView
này. Ở đây, ta sử dụng một textView
đơn giản.
Liệt kê 7. Mã cho widget textView, thiết lập từng phần tử của widget listView
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/
apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:padding="5dp" android:textStyle="bold" android:id="@+id/contactItem"> </TextView>
Lưu ý rằng theo mặc định Android cung cấp một cách bố trí đơn giản, có thể được sử dụng thay cho định nghĩa riêng của bạn. Điều này có thể được tham chiếu qua android.R.layout.simple_list_item_1
.
Tệp ManageContacts.java
Liệt kê 8 cho thấy hoạt động chính được triển khai thực hiện như thế nào. Phương thức populateContactList()
là một phương thức mà chúng ta sử dụng để truy vấn cơ sở dữ liệu các địa chỉ liên lạc và hiển thị chúng trong listView
này.
Liệt kê 8. Triển khai thực hiện của hoạt động chính
public class ManageContacts extends Activity { private ListView mContactList; private CheckBox mCheckBox; private boolean mShowStarred; private TextView selectedText; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mContactList = (ListView) findViewById(R.id.contactsListView); mCheckBox = (CheckBox) findViewById(R.id.showStarred); selectedText = (TextView) findViewById(R.id.selectedContact); mShowStarred = false; mCheckBox.setOnCheckedChangeListener(new CheckChangedListener()); mContactList.setOnItemClickListener(new ClickListener()); populateContactList(); } public void populateContactList() { Uri uri = ContactsContract.Contacts.CONTENT_URI; String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, }; String[] selectionArgs = null; String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; String selection = mShowStarred?
ContactsContract.Contacts.STARRED + " ='1'" : null; Cursor c = getContentResolver().query(uri,
projection, selection, selectionArgs, sortOrder); String[] fields = new String[] { ContactsContract.Data.DISPLAY_NAME }; SimpleCursorAdapter adapter = new
SimpleCursorAdapter(this, R.layout.contactitem, c, fields, new int[] {R.id.contactItem}); mContactList.setAdapter(adapter); } private class ClickListener implements OnItemClickListener { @Override public void onItemClick(AdapterView<?> arg0,
View textView, int pos, long arg3) { if(textView instanceof TextView) selectedText.setText(((TextView) textView).getText()); } } private class CheckChangedListener implements
OnCheckedChangeListener { @Override public void onCheckedChanged(CompoundButton
buttonView, boolean isChecked) { mShowStarred = isChecked; selectedText.setText(""); populateContactList(); } } }
Những điều cần lưu ý:
textView
màu xanh dương với tên hiển thị của địa chỉ liên lạc hiện đang được chọn. Trình lắng nghe sau là để thiết lập trường mShowStarred
và điền lại danh sách.WHERE
của SQL (ngoại trừ chính từ khóa WHERE
). Cho bằng null sẽ trả về tất cả các hàng có trong URI đã cho.?
, chúng sẽ được thay thế bằng các giá trị từ selectionArgs
, theo đúng trình tự mà chúng xuất hiện trong selection. Các giá trị này sẽ bị buộc như là kiểu chuỗi ký tự (String).ORDER BY
của SQL (ngoài trừ chính từ khóa ORDER BY
). Cho bằng null sẽ sử dụng thứ tự sắp xếp mặc định, mà theo mặc định có thể là không theo thứ tự nào cả.
Con trỏ của tập hợp kết quả đã thu được phải được liên kết với giao diện người dùng qua một bộ tiếp hợp (adapter). Chúng ta sử dụng một SimpleCursorAdapter
ở đây, mặc dù Android cũng cung cấp một ListAdapter
. Khi nhận được bộ tiếp hợp chúng ta cần phải gắn nó kèm theo vào listView
và thế là xong.
Các quyền hạn
Một bước cuối cùng trước khi ứng dụng của chúng ta sẽ chạy thành công trên một thiết bị Android là thiết lập các quyền hạn. Không có các quyền hạn để có thể đọc cơ sở dữ liệu các địa chỉ liên lạc, nhân (kernel) Linux trong thiết bị đó sẽ không cho phép các ứng dụng làm như vậy. Vì vậy, hãy vào AndroidManifest.xml>Permissions tab và thiết lập các quyền hạn sau:
android.permission.GET_ACCOUNTS
android.permission.READ_CONTACTS
Các quyền hạn này có thể được thiết lập bằng cách nhấn vào biểu tượng U và định nghĩa quyền hạn. Hình 10 cho thấy tab permissions trông như thế nào.
Hình 10. Bản kê các quyền hạn của Android
Widget listView khi sử dụng ListActivity
Ví dụ này được dùng để trình bày một cách khác để triển khai thực hiện một listView
. Trong ứng dụng trên, lưu ý rằng hoạt động chính của chúng ta triển khai thực hiện lớp hoạt động. Khi đề cập đến các widget listView
, đôi khi lớp ListActivity
tỏ ra rất tiện lợi vì nó có các API công cộng để xử lý các lần nhấn vào các mục danh sách, thiết lập các bộ tiếp hợp của danh sách, lấy vị trí nơi nhấn vào, v.v.
Chúng ta có thể sửa đổi (mã lệnh của) hoạt động của mình để triển khai thực hiện lớp ListActivity
như trong Liệt kê 9.
Liệt kê 9. Triển khai thực hiện bằng cách sử dụng lớp ListActivity
public class ManageContacts extends ListActivity { @Override protected void onListItemClick(ListView l, View v, int position, long id) { // TODO Auto-generated method stub super.onListItemClick(l, v, position, id); if(v instanceof TextView) selectedText.setText(((TextView) v).getText()); } private CheckBox mCheckBox; private boolean mShowStarred; private TextView selectedText; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mCheckBox = (CheckBox) findViewById(R.id.showStarred); selectedText = (TextView) findViewById(R.id.selectedContact); mShowStarred = false; mCheckBox.setOnCheckedChangeListener(new CheckChangedListener()); populateContactList(); } public void populateContactList() { Uri uri = ContactsContract.Contacts.CONTENT_URI; String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, }; String[] selectionArgs = null; String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; String selection = mShowStarred? ContactsContract.Contacts.STARRED + " ='1'" : null; Cursor c = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); String[] fields = new String[] { ContactsContract.Data.DISPLAY_NAME }; ListAdapter adapter = new SimpleCursorAdapter(this, R.layout.contactitem, c, fields, new int[]{R.id.contactItem}); setListAdapter(adapter); } private class CheckChangedListener implements OnCheckedChangeListener { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { mShowStarred = isChecked; selectedText.setText(""); populateContactList(); } } }
Lưu ý rằng ở đây chúng ta chỉ cần triển khai thực hiện phương thức onListItemClick
của lớp ListActivity
, thay vì khai báo một lớp ẩn danh để xử lý các lần nhấn. Ở đây, chúng ta cũng không cần phải tham chiếu đến widget listView
được xác định trong tệp main.xml vì lớp ListActivity
giả định rằng widget listView
được định nghĩa với mã định danh là @android:id/list
. Đây là lưu ý quan trọng. Bất cứ khi nào chúng ta sử dụng lớp ListActivity
, chúng ta phải định nghĩa widget listView
trong tệp main.xml để có một mã định danh @android:id/list; nếu không, lớp ListActivity
sẽ không biết tham chiếu đến listView
nào.