Bài học này hướng dẫn bạn cách truy xuất danh sách những người liên hệ có dữ liệu khớp với toàn bộ hoặc một phần của chuỗi tìm kiếm, bằng cách sử dụng các kỹ thuật sau:
- Khớp tên người liên hệ
- Truy xuất danh sách người liên hệ bằng cách so khớp chuỗi tìm kiếm với tất cả hoặc một phần của người liên hệ tên. Trình cung cấp danh bạ cho phép nhiều bản sao của cùng một tên, do đó có thể trả về danh sách các kết quả trùng khớp.
- Khớp với một loại dữ liệu cụ thể, chẳng hạn như số điện thoại
- Truy xuất danh sách địa chỉ liên hệ bằng cách so khớp chuỗi tìm kiếm với một loại chi tiết cụ thể chẳng hạn như địa chỉ email. Ví dụ: kỹ thuật này cho phép bạn liệt kê tất cả những người liên hệ có địa chỉ email khớp với chuỗi tìm kiếm.
- Khớp với bất kỳ loại dữ liệu nào
- Truy xuất danh sách liên hệ bằng cách so khớp chuỗi tìm kiếm với bất kỳ loại dữ liệu chi tiết nào, bao gồm tên, số điện thoại, địa chỉ đường phố, địa chỉ email, v.v. Ví dụ: kỹ thuật này cho phép bạn chấp nhận bất kỳ loại dữ liệu nào cho một chuỗi tìm kiếm, sau đó liệt kê những người liên hệ có dữ liệu khớp với chuỗi đó.
Lưu ý: Tất cả ví dụ trong bài học này đều sử dụng CursorLoader
để truy xuất dữ liệu từ Trình cung cấp danh bạ. CursorLoader
chạy truy vấn trên một luồng riêng biệt với luồng giao diện người dùng. Điều này đảm bảo rằng truy vấn không làm chậm giao diện người dùng
phản hồi nhanh và gây ra trải nghiệm người dùng kém. Để biết thêm thông tin, hãy xem
lớp đào tạo
Đang tải dữ liệu ở chế độ nền.
Yêu cầu quyền đọc thông tin về nhà cung cấp
Để thực hiện bất kỳ loại tìm kiếm nào của 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 điều này, hãy thêm
<uses-permission>
vào tệp kê khai của bạn dưới dạng phần tử con của
<manifest>
:
<uses-permission android:name="android.permission.READ_CONTACTS" />
So khớp một người liên hệ theo tên và liệt kê kết quả
Kỹ thuật này cố gắng so khớp một chuỗi tìm kiếm với tên của một hoặc nhiều người liên hệ trong bảng ContactsContract.Contacts
của Nhà cung cấp thông tin liên hệ. Thông thường, bạn nên hiển thị kết quả trong ListView
để cho phép người dùng chọn trong số các địa chỉ liên hệ đã so khớp.
Xác định ListView và bố cục mục
Để hiển thị kết quả tìm kiếm trong ListView
, bạn cần có một tệp bố cục chính xác định toàn bộ giao diện người dùng, bao gồm cả ListView
và một tệp bố cục mục xác định một dòng của ListView
. Ví dụ: bạn có thể tạo tệp bố cục chính res/layout/contacts_list_view.xml
bằng XML sau:
<?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent"/>
Tệp XML này sử dụng tiện ích ListView
tích hợp sẵn của Android android:id/list
.
Xác định tệp bố cục mặt hàng contacts_list_item.xml
bằng XML sau:
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true"/>
Tệp XML này sử dụng tiện ích TextView
tích hợp sẵn của Android android:text1
.
Lưu ý: Bài học này không mô tả giao diện người dùng để nhận chuỗi tìm kiếm từ người dùng, vì bạn có thể muốn nhận chuỗi này một cách gián tiếp. Ví dụ: bạn có thể cung cấp cho người dùng tuỳ chọn tìm kiếm người liên hệ có tên khớp với một chuỗi trong tin nhắn văn bản đến.
Hai tệp bố cục mà bạn đã viết xác định giao diện người dùng hiển thị ListView
. Bước tiếp theo là viết mã sử dụng giao diện người dùng này để hiển thị danh sách liên hệ.
Xác định một Mảnh hiển thị danh sách người liên hệ
Để hiển thị danh sách người liên hệ, hãy bắt đầu bằng cách xác định Fragment
do Activity
tải. Việc sử dụng Fragment
là một kỹ thuật linh hoạt hơn, vì bạn có thể sử dụng một Fragment
để hiển thị danh sách và một Fragment
thứ hai để hiển thị thông tin chi tiết về một người liên hệ mà người dùng chọn trong danh sách. Khi sử dụng phương pháp này, bạn có thể kết hợp một trong các kỹ thuật được trình bày trong bài học này với một kỹ thuật trong bài học Truy xuất thông tin chi tiết về một người liên hệ.
Để tìm hiểu cách sử dụng một hoặc nhiều đối tượng Fragment
từ một Activity
, hãy đọc lớp đào tạo Tạo giao diện người dùng động bằng Mảnh.
Để giúp bạn viết truy vấn cho Trình cung cấp danh bạ, khung Android cung cấp một lớp hợp đồng có tên là ContactsContract
. Lớp này xác định các hằng số và phương thức hữu ích để truy cập vào trình cung cấp. Khi sử dụng lớp này, bạn không cần phải
xác định hằng số của riêng bạn cho URI nội dung, tên bảng hoặc cột. Để sử dụng lớp này,
bao gồm tuyên bố sau:
Kotlin
import android.provider.ContactsContract
Java
import android.provider.ContactsContract;
Vì mã này sử dụng CursorLoader
để truy xuất dữ liệu
từ nhà cung cấp, bạn phải chỉ định rằng nhà cung cấp này sẽ triển khai giao diện trình tải
LoaderManager.LoaderCallbacks
. Ngoài ra, để giúp phát hiện người dùng chọn danh bạ nào trong danh sách kết quả tìm kiếm, hãy triển khai giao diện bộ chuyển đổi AdapterView.OnItemClickListener
. Ví dụ:
Kotlin
... import android.support.v4.app.Fragment import android.support.v4.app.LoaderManager import android.widget.AdapterView ... class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
Java
... import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.widget.AdapterView; ... public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {
Xác định biến toàn cục
Xác định các biến toàn cục được dùng trong các phần khác của mã:
Kotlin
... /* * Defines an array that contains column names to move from * the Cursor to the ListView. */ @SuppressLint("InlinedApi") private val FROM_COLUMNS: Array<String> = arrayOf( if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) { ContactsContract.Contacts.DISPLAY_NAME_PRIMARY } else { ContactsContract.Contacts.DISPLAY_NAME } ) /* * Defines an array that contains resource ids for the layout views * that get the Cursor column contents. The id is pre-defined in * the Android framework, so it is prefaced with "android.R.id" */ private val TO_IDS: IntArray = intArrayOf(android.R.id.text1) ... class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener { ... // Define global mutable variables // Define a ListView object lateinit var contactsList: ListView // Define variables for the contact the user selects // The contact's _ID value var contactId: Long = 0 // The contact's LOOKUP_KEY var contactKey: String? = null // A content URI for the selected contact var contactUri: Uri? = null // An adapter that binds the result Cursor to the ListView private val cursorAdapter: SimpleCursorAdapter? = null
Java
... /* * Defines an array that contains column names to move from * the Cursor to the ListView. */ @SuppressLint("InlinedApi") private final static String[] FROM_COLUMNS = { Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME }; /* * Defines an array that contains resource ids for the layout views * that get the Cursor column contents. The id is pre-defined in * the Android framework, so it is prefaced with "android.R.id" */ private final static int[] TO_IDS = { android.R.id.text1 }; // Define global mutable variables // Define a ListView object ListView contactsList; // Define variables for the contact the user selects // The contact's _ID value long contactId; // The contact's LOOKUP_KEY String contactKey; // A content URI for the selected contact Uri contactUri; // An adapter that binds the result Cursor to the ListView private SimpleCursorAdapter cursorAdapter; ...
Lưu ý: Vì Contacts.DISPLAY_NAME_PRIMARY
yêu cầu Android 3.0 (API phiên bản 11) trở lên, nên việc đặt minSdkVersion
của ứng dụng thành 10 trở xuống sẽ tạo ra cảnh báo Tìm lỗi mã nguồn Android trong Android Studio. Để tắt cảnh báo này, hãy thêm chú thích
@SuppressLint("InlinedApi")
trước định nghĩa FROM_COLUMNS
.
Khởi chạy mảnh
Khởi động Fragment
. Thêm hàm khởi tạo công khai và trống
theo yêu cầu của hệ thống Android và tăng cường mã của đối tượng Fragment
Giao diện người dùng trong phương thức gọi lại onCreateView()
.
Ví dụ:
Kotlin
// A UI Fragment must inflate its View override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the fragment layout return inflater.inflate(R.layout.contact_list_fragment, container, false) }
Java
// Empty public constructor, required by the system public ContactsFragment() {} // A UI Fragment must inflate its View @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the fragment layout return inflater.inflate(R.layout.contact_list_fragment, container, false); }
Thiết lập CursorAdapter cho ListView
Thiết lập SimpleCursorAdapter
liên kết các kết quả của
tìm kiếm ListView
. Để lấy đối tượng ListView
hiển thị danh bạ, bạn cần gọi Activity.findViewById()
bằng hoạt động mẹ của Fragment
. Sử dụng Context
của
hoạt động của cha mẹ khi bạn gọi setAdapter()
.
Ví dụ:
Kotlin
override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) ... // Gets the ListView from the View list of the parent activity activity?.also { contactsList = it.findViewById<ListView>(R.id.contact_list_view) // Gets a CursorAdapter cursorAdapter = SimpleCursorAdapter( it, R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0 ) // Sets the adapter for the ListView contactsList.adapter = cursorAdapter } }
Java
public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ... // Gets the ListView from the View list of the parent activity contactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view); // Gets a CursorAdapter cursorAdapter = new SimpleCursorAdapter( getActivity(), R.layout.contact_list_item, null, FROM_COLUMNS, TO_IDS, 0); // Sets the adapter for the ListView contactsList.setAdapter(cursorAdapter); }
Đặt trình nghe liên hệ đã chọn
Khi hiển thị kết quả tìm kiếm, bạn thường muốn cho phép người dùng chọn
một đầu mối liên hệ để xử lý thêm. Ví dụ: khi người dùng nhấp vào một người liên hệ, bạn có thể hiển thị địa chỉ của người liên hệ đó trên bản đồ. Để cung cấp tính năng này, trước tiên bạn xác định
Fragment
làm trình nghe lượt nhấp bằng cách chỉ định lớp
triển khai AdapterView.OnItemClickListener
, như được thể hiện trong phần
Xác định một Mảnh hiển thị danh sách người liên hệ.
Để tiếp tục thiết lập trình nghe, hãy liên kết trình nghe đó với ListView
bằng cách
gọi phương thức setOnItemClickListener()
trong onActivityCreated()
. Ví dụ:
Kotlin
fun onActivityCreated(savedInstanceState:Bundle) { ... // Set the item click listener to be the current fragment. contactsList.onItemClickListener = this ... }
Java
public void onActivityCreated(Bundle savedInstanceState) { ... // Set the item click listener to be the current fragment. contactsList.setOnItemClickListener(this); ... }
Vì bạn đã chỉ định rằng Fragment
hiện tại là
OnItemClickListener
cho
ListView
, giờ đây, bạn cần triển khai phương thức bắt buộc
onItemClick()
,
xử lý sự kiện nhấp chuột. Điều này được mô tả trong phần tiếp theo.
Xác định một phép chiếu
Xác định một hằng số chứa các cột mà bạn muốn trả về qua truy vấn. Mỗi mục trong ListView
hiển thị tên hiển thị của người liên hệ, chứa dạng chính của tên người liên hệ. Trong Android 3.0 (API phiên bản 11) trở lên,
tên của cột này là
Contacts.DISPLAY_NAME_PRIMARY
; trong các phiên bản trước đó, tên của nó là
Contacts.DISPLAY_NAME
.
Cột Contacts._ID
được sử dụng trong quy trình liên kết SimpleCursorAdapter
.
Contacts._ID
và
LOOKUP_KEY
được sử dụng cùng nhau để
tạo URI nội dung cho địa chỉ liên hệ mà người dùng chọn.
Kotlin
... @SuppressLint("InlinedApi") private val PROJECTION: Array<out String> = arrayOf( ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ContactsContract.Contacts.DISPLAY_NAME_PRIMARY else ContactsContract.Contacts.DISPLAY_NAME )
Java
... @SuppressLint("InlinedApi") private static final String[] PROJECTION = { Contacts._ID, Contacts.LOOKUP_KEY, Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME };
Xác định hằng số cho chỉ mục cột Con trỏ
Để tải dữ liệu từ một cột riêng lẻ trong Cursor
, bạn cần
chỉ mục của cột trong Cursor
. Bạn có thể định nghĩa các hằng số
cho các chỉ mục của cột Cursor
, vì các chỉ mục đều
giống như thứ tự của tên cột trong phép chiếu. Ví dụ:
Kotlin
// The column index for the _ID column private const val CONTACT_ID_INDEX: Int = 0 // The column index for the CONTACT_KEY column private const val CONTACT_KEY_INDEX: Int = 1
Java
// The column index for the _ID column private static final int CONTACT_ID_INDEX = 0; // The column index for the CONTACT_KEY column private static final int CONTACT_KEY_INDEX = 1;
Xác định tiêu chí lựa chọn
Để chỉ định dữ liệu bạn muốn, hãy tạo một tổ hợp biểu thức văn bản và biến để cho nhà cung cấp biết các cột dữ liệu cần tìm kiếm và giá trị cần tìm.
Đối với biểu thức văn bản, hãy xác định một hằng số liệt kê các cột tìm kiếm. Mặc dù biểu thức này cũng có thể chứa các giá trị, nhưng bạn nên biểu thị các giá trị bằng phần giữ chỗ "?". Trong quá trình truy xuất, phần giữ chỗ được thay thế bằng các giá trị từ một mảng. Việc sử dụng "?" làm phần giữ chỗ đảm bảo rằng thông số kỹ thuật 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 giúp loại bỏ khả năng xảy ra lỗi SQL độc hại tiêm. Ví dụ:
Kotlin
// Defines the text expression @SuppressLint("InlinedApi") private val SELECTION: String = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} LIKE ?" else "${ContactsContract.Contacts.DISPLAY_NAME} LIKE ?" ... // Defines a variable for the search string private val searchString: String = ... // Defines the array to hold values that replace the ? private val selectionArgs = arrayOf<String>(searchString)
Java
// Defines the text expression @SuppressLint("InlinedApi") private static final String SELECTION = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" : Contacts.DISPLAY_NAME + " LIKE ?"; // Defines a variable for the search string private String searchString; // Defines the array to hold values that replace the ? private String[] selectionArgs = { searchString };
Xác định phương thức onItemClick()
Ở phần trước, bạn đã thiết lập trình nghe lượt nhấp vào mục cho ListView
.
Bây giờ, hãy triển khai thao tác cho trình nghe bằng cách xác định phương thức
AdapterView.OnItemClickListener.onItemClick()
:
Kotlin
override fun onItemClick(parent: AdapterView<*>, view: View?, position: Int, id: Long) { // Get the Cursor val cursor: Cursor? = (parent.adapter as? CursorAdapter)?.cursor?.apply { // Move to the selected contact moveToPosition(position) // Get the _ID value contactId = getLong(CONTACT_ID_INDEX) // Get the selected LOOKUP KEY contactKey = getString(CONTACT_KEY_INDEX) // Create the contact's content Uri contactUri = ContactsContract.Contacts.getLookupUri(contactId, mContactKey) /* * You can use contactUri as the content URI for retrieving * the details for a contact. */ } }
Java
@Override public void onItemClick( AdapterView<?> parent, View item, int position, long rowID) { // Get the Cursor Cursor cursor = parent.getAdapter().getCursor(); // Move to the selected contact cursor.moveToPosition(position); // Get the _ID value contactId = cursor.getLong(CONTACT_ID_INDEX); // Get the selected LOOKUP KEY contactKey = cursor.getString(CONTACT_KEY_INDEX); // Create the contact's content Uri contactUri = Contacts.getLookupUri(contactId, mContactKey); /* * You can use contactUri as the content URI for retrieving * the details for a contact. */ }
Khởi chạy trình tải
Vì đang sử dụng CursorLoader
để truy xuất dữ liệu, nên bạn phải khởi chạy luồng trong nền và các biến khác kiểm soát quá trình truy xuất không đồng bộ. Thực hiện khởi tạo trong
onCreate()
dưới dạng
như trong ví dụ sau:
Kotlin
class ContactsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> { ... override fun onCreate(savedInstanceState: Bundle?) { // Always call the super method first super.onCreate(savedInstanceState) ... // Initializes the loader loaderManager.initLoader(0, null, this)
Java
public class ContactsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { ... // Called just before the Fragment displays its UI @Override public void onCreate(Bundle savedInstanceState) { // Always call the super method first super.onCreate(savedInstanceState); ... // Initializes the loader getLoaderManager().initLoader(0, null, this);
Triển khai phương thức onCreateLoader()
Triển khai phương thức onCreateLoader()
. Phương thức này được khung trình tải gọi ngay sau khi bạn gọi initLoader()
.
Trong onCreateLoader()
, hãy thiết lập mẫu chuỗi tìm kiếm. Để chuyển một chuỗi thành mẫu, hãy chèn các ký tự "%" (phần trăm) để biểu thị một chuỗi ký tự từ 0 trở lên hoặc các ký tự "_" (dấu gạch dưới) để biểu thị một ký tự hoặc cả hai. Ví dụ: mẫu "%Jefferson%"
sẽ khớp với cả "Thomas Jefferson" và "Jefferson Davis".
Trả về một CursorLoader
mới từ phương thức này. Đối với URI nội dung, hãy sử dụng Contacts.CONTENT_URI
.
URI này tham chiếu đến toàn bộ bảng, như trong ví dụ sau:
Kotlin
... override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { /* * Makes search string into pattern and * stores it in the selection array */ selectionArgs[0] = "%$mSearchString%" // Starts the query return activity?.let { return CursorLoader( it, ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ) } ?: throw IllegalStateException() }
Java
... @Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Makes search string into pattern and * stores it in the selection array */ selectionArgs[0] = "%" + searchString + "%"; // Starts the query return new CursorLoader( getActivity(), ContactsContract.Contacts.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ); }
Triển khai onLoadFinished() và onLoaderReset()
Triển khai phương thức 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. Trong phương thức này, hãy đặt giá trị
kết quả Cursor
trong
SimpleCursorAdapter
. Thao tác này sẽ tự động cập nhật
ListView
với các kết quả tìm kiếm:
Kotlin
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Put the result Cursor in the adapter for the ListView cursorAdapter?.swapCursor(cursor) }
Java
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Put the result Cursor in the adapter for the ListView cursorAdapter.swapCursor(cursor); }
Phương thức onLoaderReset()
được gọi khi khung trình tải phát hiện kết quả Cursor
chứa dữ liệu cũ. Xoá
SimpleCursorAdapter
tham chiếu đến hiện có
Cursor
. Nếu không, khung trình tải sẽ không tái chế Cursor
, gây ra sự cố rò rỉ bộ nhớ. Ví dụ:
Kotlin
override fun onLoaderReset(loader: Loader<Cursor>) { // Delete the reference to the existing Cursor cursorAdapter?.swapCursor(null) }
Java
@Override public void onLoaderReset(Loader<Cursor> loader) { // Delete the reference to the existing Cursor cursorAdapter.swapCursor(null); }
Giờ đây, bạn đã có các phần chính của một ứng dụng so khớp chuỗi tìm kiếm với tên người liên hệ và trả về kết quả trong ListView
. Người dùng có thể nhấp vào tên người liên hệ để chọn.
Thao tác này kích hoạt trình nghe, trong đó bạn có thể làm việc thêm với dữ liệu của người liên hệ. Ví dụ:
bạn có thể truy xuất thông tin chi tiết của địa chỉ liên hệ đó. Để tìm hiểu cách thực hiện việc này, hãy tiếp tục với bài học tiếp theo: Truy xuất thông tin chi tiết về một người liên hệ.
Để tìm hiểu thêm về giao diện người dùng tìm kiếm, hãy đọc hướng dẫn về API Tạo giao diện tìm kiếm.
Các phần còn lại trong bài học này minh hoạ các cách khác để tìm người liên hệ trong Nhà cung cấp danh bạ.
So khớp một người liên hệ theo một loại dữ liệu cụ thể
Kỹ thuật này cho phép bạn chỉ định loại dữ liệu mà bạn muốn so khớp. Đang truy xuất theo tên là ví dụ cụ thể về loại truy vấn này, nhưng bạn cũng có thể thực hiện đối với bất kỳ loại truy vấn nào dữ liệu chi tiết liên quan đến một địa chỉ liên hệ. Ví dụ: bạn có thể truy xuất những người liên hệ có một mã bưu chính cụ thể; trong trường hợp này, chuỗi tìm kiếm phải khớp với dữ liệu được lưu trữ trong hàng mã bưu chính.
Để triển khai loại truy xuất này, trước tiên hãy triển khai mã sau, như được liệt kê trong các phần trước:
- Yêu cầu quyền để đọc Nhà cung cấp.
- Xác định bố cục ListView và mục.
- Xác định một Mảnh hiển thị danh sách người liên hệ.
- Xác định biến toàn cục.
- Khởi động Mảnh.
- Thiết lập CursorAdapter cho ListView.
- Thiết lập trình nghe người liên hệ đã chọn.
-
Xác định hằng số cho chỉ mục cột Con trỏ.
Mặc dù bạn đang truy xuất dữ liệu từ một bảng khác, thứ tự của các cột trong phép chiếu giống nhau, vì vậy bạn có thể sử dụng cùng một chỉ mục cho Con trỏ.
- Xác định phương thức onItemClick().
- Khởi chạy trình tải.
- Triển khai onLoadCompleted() và onLoaderReset().
Các bước sau đây sẽ cho bạn biết mã bổ sung mà bạn cần để so khớp một chuỗi tìm kiếm loại dữ liệu chi tiết cụ thể rồi hiển thị kết quả.
Chọn loại dữ liệu và bảng
Để tìm kiếm một loại dữ liệu chi tiết cụ thể, bạn phải biết giá trị loại MIME tuỳ chỉnh
cho loại dữ liệu. Mỗi loại dữ liệu có một giá trị loại MIME duy nhất được xác định bằng hằng số CONTENT_ITEM_TYPE
trong lớp con của ContactsContract.CommonDataKinds
liên kết với loại dữ liệu đó.
Các lớp con có tên cho biết loại dữ liệu của chúng; ví dụ: lớp con cho email
dữ liệu là ContactsContract.CommonDataKinds.Email
và MIME tuỳ chỉnh
Loại dữ liệu email được xác định theo hằng số
Email.CONTENT_ITEM_TYPE
.
Sử dụng bảng ContactsContract.Data
cho nội dung tìm kiếm của bạn. Tất cả các hằng số bạn cần cho phép chiếu, mệnh đề lựa chọn và thứ tự sắp xếp được xác định trong hoặc kế thừa từ bảng này.
Xác định phép chiếu
Để xác định một phép chiếu, hãy chọn một hoặc nhiều cột được xác định trong ContactsContract.Data
hoặc các lớp mà phép chiếu đó kế thừa. Chiến lược phát hành đĩa đơn
Trình cung cấp danh bạ thực hiện kết hợp ngầm ẩn giữa ContactsContract.Data
và các bảng khác trước khi trả về các hàng. Ví dụ:
Kotlin
@SuppressLint("InlinedApi") private val PROJECTION: Array<out String> = arrayOf( /* * The detail data row ID. To make a ListView work, * this column is required. */ ContactsContract.Data._ID, // The primary display name if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ContactsContract.Data.DISPLAY_NAME_PRIMARY else ContactsContract.Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI ContactsContract.Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI ContactsContract.Data.LOOKUP_KEY )
Java
@SuppressLint("InlinedApi") private static final String[] PROJECTION = { /* * The detail data row ID. To make a ListView work, * this column is required. */ ContactsContract.Data._ID, // The primary display name Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? ContactsContract.Data.DISPLAY_NAME_PRIMARY : ContactsContract.Data.DISPLAY_NAME, // The contact's _ID, to construct a content URI ContactsContract.Data.CONTACT_ID, // The contact's LOOKUP_KEY, to construct a content URI ContactsContract.Data.LOOKUP_KEY // A permanent link to the contact };
Xác định tiêu chí tìm kiếm
Để tìm kiếm một chuỗi trong một loại dữ liệu cụ thể, hãy tạo mệnh đề lựa chọn từ các mệnh đề sau:
-
Tên của cột chứa chuỗi tìm kiếm. Tên này thay đổi theo loại dữ liệu, vì vậy, bạn cần tìm lớp con của
ContactsContract.CommonDataKinds
tương ứng với loại dữ liệu, sau đó chọn tên cột trong lớp con đó. Ví dụ: để tìm kiếm địa chỉ email, hãy sử dụng cộtEmail.ADDRESS
. - Chính chuỗi tìm kiếm, được biểu thị dưới dạng "?" trong mệnh đề lựa chọn.
-
Tên của cột chứa giá trị loại MIME tuỳ chỉnh. Tên này luôn là
Data.MIMETYPE
. -
Giá trị loại MIME tuỳ chỉnh cho loại dữ liệu. Như mô tả trước đó, đây là hằng số
CONTENT_ITEM_TYPE
trong lớp conContactsContract.CommonDataKinds
. Ví dụ: MIME Giá trị loại cho dữ liệu email làEmail.CONTENT_ITEM_TYPE
. Giới hạn giá trị trong dấu ngoặc đơn bằng cách nối ký tự "'
" (dấu ngoặc đơn) vào đầu và cuối hằng số; nếu không, trình cung cấp sẽ diễn giải giá trị này là tên biến thay vì 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 đang sử dụng một hằng số thay vì giá trị do người dùng cung cấp.
Ví dụ:
Kotlin
/* * Constructs search criteria from the search string * and email MIME type */ private val SELECTION: String = /* * Searches for an email address * that matches the search string */ "${Email.ADDRESS} LIKE ? AND " + /* * Searches for a MIME type that matches * the value of the constant * Email.CONTENT_ITEM_TYPE. Note the * single quotes surrounding Email.CONTENT_ITEM_TYPE. */ "${ContactsContract.Data.MIMETYPE } = '${Email.CONTENT_ITEM_TYPE}'"
Java
/* * Constructs search criteria from the search string * and email MIME type */ private static final String SELECTION = /* * Searches for an email address * that matches the search string */ Email.ADDRESS + " LIKE ? " + "AND " + /* * Searches for a MIME type that matches * the value of the constant * Email.CONTENT_ITEM_TYPE. Note the * single quotes surrounding Email.CONTENT_ITEM_TYPE. */ ContactsContract.Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
Tiếp theo, hãy xác định các biến để chứa đối số lựa chọn:
Kotlin
private var searchString: String? = null private val selectionArgs: Array<String> = arrayOf("")
Java
String searchString; String[] selectionArgs = { "" };
Triển khai onCreateLoader()
Bây giờ, bạn đã chỉ định dữ liệu bạn muốn và cách tìm dữ liệu, hãy xác định truy vấn trong
triển khai onCreateLoader()
.
Trả về một CursorLoader
mới từ phương thức này, sử dụng phép chiếu, biểu thức văn bản lựa chọn và mảng lựa chọn làm đối số. Đối với URI nội dung, hãy sử dụng Data.CONTENT_URI
. Ví dụ:
Kotlin
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { // OPTIONAL: Makes search string into pattern searchString = "%$mSearchString%" searchString?.also { // Puts the search string into the selection criteria selectionArgs[0] = it } // Starts the query return activity?.let { CursorLoader( it, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ) } ?: throw IllegalStateException() }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { // OPTIONAL: Makes search string into pattern searchString = "%" + searchString + "%"; // Puts the search string into the selection criteria selectionArgs[0] = searchString; // Starts the query return new CursorLoader( getActivity(), Data.CONTENT_URI, PROJECTION, SELECTION, selectionArgs, null ); }
Các đoạn mã này là cơ sở của một tra cứu đảo ngược đơn giản dựa trên loại chi tiết cụ thể . Đây là kỹ thuật tốt nhất để sử dụng nếu ứng dụng của bạn tập trung vào một loại dữ liệu cụ thể, chẳng hạn như email, và bạn muốn cho phép người dùng nhận tên liên kết với một phần dữ liệu.
So khớp một người liên hệ theo bất kỳ loại dữ liệu nào
Việc truy xuất một người liên hệ dựa trên bất kỳ loại dữ liệu nào sẽ trả về người liên hệ nếu có bất kỳ dữ liệu nào của họ khớp với chuỗi tìm kiếm, bao gồm tên, địa chỉ email, địa chỉ bưu chính, số điện thoại, v.v. Điều này dẫn đến một tập hợp kết quả tìm kiếm rộng. Ví dụ: nếu chuỗi tìm kiếm là "Doe", sau đó tìm kiếm bất kỳ loại dữ liệu nào sẽ trả về địa chỉ liên hệ "John Doe"; nó cũng trả về người liên hệ sống trên "Phố Doe".
Để triển khai loại truy xuất này, trước tiên hãy triển khai mã sau, như được liệt kê trong các phần trước:
- Yêu cầu quyền để đọc Nhà cung cấp.
- Xác định bố cục ListView và mục.
- Xác định một Mảnh hiển thị danh sách người liên hệ.
- Xác định biến toàn cục.
- Khởi động Mảnh.
- Thiết lập CursorAdapter cho ListView.
- Đặt trình nghe liên hệ đã chọn.
- Xác định một phép chiếu.
-
Xác định hằng số cho chỉ mục cột Con trỏ.
Đối với loại truy xuất này, bạn sẽ sử dụng cùng một bảng mà bạn đã sử dụng trong phần So khớp một người liên hệ theo tên và liệt kê kết quả. Sử dụng chỉ mục cột tương tự.
- Xác định phương thức onItemClick().
- Khởi chạy trình tải.
- Triển khai onLoadCompleted() và onLoaderReset().
Các bước sau đây cho bạn thấy mã bổ sung cần thiết để so khớp một chuỗi tìm kiếm với bất kỳ loại dữ liệu nào và hiển thị kết quả.
Xoá tiêu chí lựa chọn
Không xác định hằng số SELECTION
hoặc biến mSelectionArgs
.
Các giá trị này không được dùng trong loại truy xuất này.
Triển khai onCreateLoader()
Triển khai onCreateLoader()
trả về một CursorLoader
mới.
Bạn không cần chuyển đổi chuỗi tìm kiếm thành mẫu vì Trình cung cấp danh bạ sẽ tự động thực hiện việc đó. Sử dụng Contacts.CONTENT_FILTER_URI
làm URI cơ sở và nối chuỗi tìm kiếm vào URI đó bằng cách gọi Uri.withAppendedPath()
. Việc sử dụng URI này sẽ tự động kích hoạt tính năng tìm kiếm cho bất kỳ loại dữ liệu nào, như trong ví dụ sau:
Kotlin
override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> { /* * Appends the search string to the base URI. Always * encode search strings to ensure they're in proper * format. */ val contentUri: Uri = Uri.withAppendedPath( ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode(searchString) ) // Starts the query return activity?.let { CursorLoader( it, contentUri, PROJECTION2, null, null, null ) } ?: throw IllegalStateException() }
Java
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Appends the search string to the base URI. Always * encode search strings to ensure they're in proper * format. */ Uri contentUri = Uri.withAppendedPath( Contacts.CONTENT_FILTER_URI, Uri.encode(searchString)); // Starts the query return new CursorLoader( getActivity(), contentUri, PROJECTION, null, null, null ); }
Các đoạn mã này là cơ sở của ứng dụng để thực hiện tìm kiếm rộng rãi về Trình cung cấp danh bạ. Kỹ thuật này hữu ích cho các ứng dụng muốn triển khai chức năng tương tự như màn hình danh bạ của ứng dụng People.