Bài học này hướng dẫn cách truy xuất dữ liệu chi tiết của một người liên hệ, chẳng hạn như địa chỉ email, số điện thoại, v.v. Đây là thông tin chi tiết mà người dùng tìm kiếm khi truy xuất một người liên hệ. Bạn có thể cung cấp cho họ tất cả thông tin liên hệ hoặc chỉ hiển thị chi tiết thuộc một loại cụ thể, chẳng hạn như địa chỉ email.
Các bước trong bài học này giả định rằng bạn đã có một
ContactsContract.Contacts
hàng cho một địa chỉ liên hệ mà người dùng đã chọn.
Bài học Truy xuất tên người liên hệ hướng dẫn cách
truy xuất danh sách địa chỉ liên hệ.
Truy xuất tất cả thông tin chi tiết về một người liên hệ
Để truy xuất tất cả chi tiết về một địa chỉ liên hệ, hãy tìm kiếm
Bảng ContactsContract.Data
cho bất kỳ hàng nào có chứa thông tin của địa chỉ liên hệ
LOOKUP_KEY
. Cột này có trong bảng ContactsContract.Data
vì Trình cung cấp danh bạ thực hiện một mối liên kết ngầm ẩn giữa bảng ContactsContract.Contacts
và bảng ContactsContract.Data
. Chiến lược phát hành đĩa đơn
Nội dung mô tả về cột LOOKUP_KEY
chi tiết hơn trong bài học Truy xuất tên người liên hệ.
Lưu ý: Việc truy xuất tất cả thông tin chi tiết về một người liên hệ sẽ làm giảm hiệu suất của thiết bị, vì thiết bị cần truy xuất tất cả các cột trong bảng ContactsContract.Data
. Hãy cân nhắc tác động đến hiệu suất trước khi sử dụng kỹ thuật này.
Yêu cầu cấp quyền
Để đọc từ Trình cung cấp danh bạ, ứng dụng của bạn phải có
Quyền READ_CONTACTS
.
Để yêu cầu quyền này, hãy thêm phần tử con sau đây của
<manifest>
vào tệp kê khai của bạn:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Thiết lập phép chiếu
Tuỳ thuộc vào loại dữ liệu trong một hàng, hàng có thể chỉ sử dụng một vài hoặc nhiều cột. Ngoài ra, dữ liệu nằm trong các cột khác nhau tuỳ thuộc vào loại dữ liệu.
Để đảm bảo bạn nhận được tất cả các cột có thể có cho tất cả các loại dữ liệu có thể, bạn cần thêm tất cả
tên cột vào phép chiếu. Luôn truy xuất
Data._ID
nếu bạn đang liên kết kết quả
Cursor
sang ListView
; nếu không, ràng buộc
sẽ không hoạt động. Đồng thời truy xuất Data.MIMETYPE
để bạn có thể xác định loại dữ liệu
của mỗi hàng bạn truy xuất. Ví dụ:
Kotlin
private val PROJECTION: Array<out String> = arrayOf( ContactsContract.Data._ID, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, ContactsContract.Data.DATA2, ContactsContract.Data.DATA3, ContactsContract.Data.DATA4, ContactsContract.Data.DATA5, ContactsContract.Data.DATA6, ContactsContract.Data.DATA7, ContactsContract.Data.DATA8, ContactsContract.Data.DATA9, ContactsContract.Data.DATA10, ContactsContract.Data.DATA11, ContactsContract.Data.DATA12, ContactsContract.Data.DATA13, ContactsContract.Data.DATA14, ContactsContract.Data.DATA15 )
Java
private static final String[] PROJECTION = { ContactsContract.Data._ID, ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1, ContactsContract.Data.DATA2, ContactsContract.Data.DATA3, ContactsContract.Data.DATA4, ContactsContract.Data.DATA5, ContactsContract.Data.DATA6, ContactsContract.Data.DATA7, ContactsContract.Data.DATA8, ContactsContract.Data.DATA9, ContactsContract.Data.DATA10, ContactsContract.Data.DATA11, ContactsContract.Data.DATA12, ContactsContract.Data.DATA13, ContactsContract.Data.DATA14, ContactsContract.Data.DATA15 };
Bản chiếu này truy xuất tất cả các cột cho một hàng trong bảng ContactsContract.Data
, sử dụng tên cột được xác định trong lớp ContactsContract.Data
.
Nếu muốn, bạn cũng có thể sử dụng bất kỳ hằng số cột nào khác được xác định trong hoặc kế thừa bởi
Lớp ContactsContract.Data
. Tuy nhiên, hãy lưu ý rằng các cột SYNC1
đến SYNC4
được dùng cho bộ điều hợp đồng bộ hoá, vì vậy, dữ liệu của các cột này không hữu ích.
Xác định tiêu chí lựa chọn
Xác định một hằng số cho mệnh đề lựa chọn, một mảng để lưu trữ các đối số lựa chọn và một biến để lưu trữ giá trị lựa chọn. Sử dụng
cột Contacts.LOOKUP_KEY
thành
tìm người liên hệ đó. Ví dụ:
Kotlin
// Defines the selection clause private const val SELECTION: String = "${ContactsContract.Data.LOOKUP_KEY} = ?" ... // Defines the array to hold the search criteria private val selectionArgs: Array<String> = arrayOf("") /* * Defines a variable to contain the selection value. Once you * have the Cursor from the Contacts table, and you've selected * the desired row, move the row's LOOKUP_KEY value into this * variable. */ private var lookupKey: String? = null
Java
// Defines the selection clause private static final String SELECTION = Data.LOOKUP_KEY + " = ?"; // Defines the array to hold the search criteria private String[] selectionArgs = { "" }; /* * Defines a variable to contain the selection value. Once you * have the Cursor from the Contacts table, and you've selected * the desired row, move the row's LOOKUP_KEY value into this * variable. */ private lateinit var lookupKey: String
Đang dùng dấu "?" làm trình giữ chỗ trong biểu thức văn bản lựa chọn của bạn đảm bảo rằng kết quả tìm kiếm được tạo bằng cách liên kết thay vì biên dịch SQL. Phương pháp này loại bỏ khả năng chèn SQL độc hại.
Xác định thứ tự sắp xếp
Xác định thứ tự sắp xếp bạn muốn trong kết quả Cursor
. Để giữ tất cả các hàng cho một loại dữ liệu cụ thể với nhau, hãy sắp xếp theo Data.MIMETYPE
. Đối số truy vấn này nhóm tất cả các hàng email với nhau, tất cả các hàng điện thoại với nhau, v.v. Ví dụ:
Kotlin
/* * Defines a string that specifies a sort order of MIME type */ private const val SORT_ORDER = ContactsContract.Data.MIMETYPE
Java
/* * Defines a string that specifies a sort order of MIME type */ private static final String SORT_ORDER = ContactsContract.Data.MIMETYPE;
Lưu ý: Một số loại dữ liệu không sử dụng loại phụ, vì vậy, bạn không thể sắp xếp theo loại phụ.
Thay vào đó, bạn phải lặp lại thông qua Cursor
được trả về,
xác định loại dữ liệu của hàng hiện tại và lưu trữ dữ liệu cho các hàng sử dụng loại phụ. Khi đọc xong con trỏ, bạn có thể sắp xếp từng loại dữ liệu theo loại phụ và hiển thị kết quả.
Khởi chạy trình tải
Luôn truy xuất từ Trình cung cấp danh bạ (và tất cả các trình cung cấp nội dung khác) trong
luồng trong nền. Sử dụng khung Trình tải được xác định bằng
Lớp LoaderManager
và
Giao diện LoaderManager.LoaderCallbacks
để làm nền
truy xuất.
Khi bạn đã sẵn sàng truy xuất các hàng, hãy khởi chạy khung trình tải bằng cách
đang gọi initLoader()
. Truyền một
giá trị nhận dạng số nguyên cho phương thức; giá trị nhận dạng này được chuyển đến
LoaderManager.LoaderCallbacks
phương thức. Giá trị nhận dạng này giúp bạn sử dụng nhiều trình tải trong một ứng dụng bằng cách cho phép bạn phân biệt giữa các trình tải đó.
Đoạn mã sau đây cho biết cách khởi chạy khung trình tải:
Kotlin
// Defines a constant that identifies the loader private const val DETAILS_QUERY_ID: Int = 0 class DetailsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> { ... override fun onCreate(savedInstanceState: Bundle?) { ... // Initializes the loader framework loaderManager.initLoader(DETAILS_QUERY_ID, null, this)
Java
public class DetailsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Defines a constant that identifies the loader static int DETAILS_QUERY_ID = 0; ... @Override public void onCreate(Bundle savedInstanceState) { ... // Initializes the loader framework getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);
Triển khai phương thức onCreateLoader()
Triển khai phương thức onCreateLoader()
mà khung trình tải sẽ gọi ngay sau khi bạn gọi
initLoader()
. Trả về một CursorLoader
từ phương thức này. Vì bạn đang tìm kiếm bảng ContactsContract.Data
, hãy sử dụng hằng số Data.CONTENT_URI
làm URI nội dung.
Ví dụ:
Kotlin
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { // Choose the proper action mLoader = when(loaderId) { DETAILS_QUERY_ID -> { // Assigns the selection parameter selectionArgs[0] = lookupKey // Starts the query activity?.let { CursorLoader( it, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ) } } ... } return mLoader }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // Choose the proper action switch (loaderId) { case DETAILS_QUERY_ID: // Assigns the selection parameter selectionArgs[0] = lookupKey; // Starts the query CursorLoader mLoader = new CursorLoader( getActivity(), ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, SORT_ORDER ); }
Triển khai onLoadComplete() và onLoaderReset()
Triển khai
onLoadFinished()
. Khung của trình tải sẽ gọi
onLoadFinished()
khi Trình cung cấp danh bạ trả về kết quả truy vấn. Ví dụ:
Kotlin
override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) { when(loader.id) { DETAILS_QUERY_ID -> { /* * Process the resulting Cursor here. */ } ... } }
Java
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { switch (loader.getId()) { case DETAILS_QUERY_ID: /* * Process the resulting Cursor here. */ } break; ... } }
Phương thức onLoaderReset()
được gọi khi khung trình tải phát hiện thấy dữ liệu sao lưu kết quả Cursor
đã thay đổi. Tại thời điểm này, hãy xoá mọi tệp tham chiếu hiện có
đến Cursor
bằng cách đặt các tệp tham chiếu đó thành rỗng. Nếu không, trình tải
khung này sẽ không huỷ bỏ Cursor
cũ và bạn sẽ nhận được một bộ nhớ
rò rỉ. Ví dụ:
Kotlin
override fun onLoaderReset(loader: Loader<Cursor>) { when (loader.id) { DETAILS_QUERY_ID -> { /* * If you have current references to the Cursor, * remove them here. */ } ... } }
Java
@Override public void onLoaderReset(Loader<Cursor> loader) { switch (loader.getId()) { case DETAILS_QUERY_ID: /* * If you have current references to the Cursor, * remove them here. */ } break; }
Truy xuất thông tin cụ thể về một người liên hệ
Việc truy xuất một loại dữ liệu cụ thể cho một người liên hệ, chẳng hạn như tất cả email, đều tuân theo cùng một mẫu khi truy xuất tất cả thông tin chi tiết. Đây là những thay đổi duy nhất bạn cần thực hiện đối với mã được liệt kê trong phần Truy xuất tất cả thông tin chi tiết về một người liên hệ:
- Dự đoán
-
Sửa đổi phép chiếu của bạn để truy xuất các cột dành riêng cho
loại dữ liệu của bạn. Ngoài ra, hãy sửa đổi phép chiếu để sử dụng các hằng số tên cột được xác định trong lớp con
ContactsContract.CommonDataKinds
tương ứng với loại dữ liệu. - Lựa chọn
-
Sửa đổi văn bản đã chọn để tìm kiếm giá trị
MIMETYPE
dành riêng cho loại dữ liệu của bạn. - Thứ tự sắp xếp
-
Vì bạn chỉ chọn một loại chi tiết, nên đừng nhóm
Cursor
được trả về theoData.MIMETYPE
.
Những nội dung sửa đổi này được mô tả trong các phần sau.
Xác định phép chiếu
Xác định các cột mà bạn muốn truy xuất bằng cách sử dụng hằng số tên cột trong lớp con của ContactsContract.CommonDataKinds
cho loại dữ liệu.
Nếu bạn dự định liên kết Cursor
với ListView
, hãy nhớ truy xuất cột _ID
. Ví dụ: để truy xuất dữ liệu email, hãy xác định
phép chiếu sau:
Kotlin
private val PROJECTION: Array<String> = arrayOf( ContactsContract.CommonDataKinds.Email._ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.LABEL )
Java
private static final String[] PROJECTION = { ContactsContract.CommonDataKinds.Email._ID, ContactsContract.CommonDataKinds.Email.ADDRESS, ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.LABEL };
Xin lưu ý rằng phép chiếu này sử dụng tên cột được xác định trong lớp ContactsContract.CommonDataKinds.Email
, thay vì tên cột được xác định trong lớp ContactsContract.Data
. Việc sử dụng tên cột dành riêng cho email giúp mã dễ đọc hơn.
Trong phép chiếu, bạn cũng có thể sử dụng bất kỳ cột nào khác được xác định trong
Lớp con ContactsContract.CommonDataKinds
.
Xác định tiêu chí lựa chọn
Xác định một biểu thức văn bản tìm kiếm truy xuất các hàng cho LOOKUP_KEY
của một người liên hệ cụ thể và Data.MIMETYPE
của thông tin chi tiết mà bạn muốn. Đưa giá trị MIMETYPE
vào trong
dấu nháy đơn bằng cách nối "'
" ký tự (dấu ngoặc đơn) ở đầu và cuối
của hằng số; nếu không, trình cung cấp diễn giải hằng số là tên biến thay vì
so với giá trị chuỗi. Bạn không cần sử dụng phần giữ chỗ cho giá trị này vì bạn
sử dụng hằng số thay vì giá trị do người dùng cung cấp. Ví dụ:
Kotlin
/* * Defines the selection clause. Search for a lookup key * and the Email MIME type */ private const val SELECTION = "${ContactsContract.Data.LOOKUP_KEY} = ? AND " + "${ContactsContract.Data.MIMETYPE} = '${Email.CONTENT_ITEM_TYPE}'" ... // Defines the array to hold the search criteria private val selectionArgs: Array<String> = arrayOf("")
Java
/* * Defines the selection clause. Search for a lookup key * and the Email MIME type */ private static final String SELECTION = Data.LOOKUP_KEY + " = ?" + " AND " + Data.MIMETYPE + " = " + "'" + Email.CONTENT_ITEM_TYPE + "'"; // Defines the array to hold the search criteria private String[] selectionArgs = { "" };
Xác định thứ tự sắp xếp
Xác định thứ tự sắp xếp cho Cursor
được trả về. Vì bạn đang truy xuất một
loại dữ liệu cụ thể, bỏ qua cách sắp xếp trên MIMETYPE
.
Thay vào đó, nếu loại dữ liệu chi tiết mà bạn đang tìm kiếm có một loại phụ, hãy sắp xếp theo loại phụ đó.
Ví dụ: đối với dữ liệu email, bạn có thể sắp xếp theo
Email.TYPE
:
Kotlin
private const val SORT_ORDER: String = "${Email.TYPE} ASC"
Java
private static final String SORT_ORDER = Email.TYPE + " ASC ";