Z tej lekcji dowiesz się, jak pobrać szczegółowe dane kontaktu, takie jak adresy e-mail, numery telefonów itd. To szczegółowe informacje, których szukają użytkownicy po odzyskiwaniu kontaktu. Możesz podać wszystkie szczegóły kontaktu lub tylko szczegóły określonego typu, np. adresy e-mail.
W krokach w tej lekcji zakładamy, że masz już wiersz ContactsContract.Contacts
dotyczący kontaktu wybranego przez użytkownika.
W wykładzie Pobieranie nazw kontaktów dowiesz się, jak pobrać listę kontaktów.
Pobieranie wszystkich szczegółów kontaktu
Aby pobrać wszystkie szczegóły kontaktu, wyszukaj w tabeli ContactsContract.Data
wiersze zawierające jego LOOKUP_KEY
. Ta kolumna jest dostępna w tabeli ContactsContract.Data
, ponieważ dostawca kontaktów tworzy niejawne złączenie między tabelą ContactsContract.Contacts
a tabelą ContactsContract.Data
. Kolumna LOOKUP_KEY
jest szczegółowo opisana w lekcji Pobieranie nazw kontaktów.
Uwaga: pobranie wszystkich informacji o kontakcie zmniejsza wydajność urządzenia, ponieważ musi ono pobrać wszystkie kolumny w tabeli ContactsContract.Data
. Zanim skorzystasz z tej metody, weź pod uwagę wpływ na wydajność.
Poproś o uprawnienia
Aby odczytywać dane z dostawcy kontaktów, aplikacja musi mieć uprawnienie READ_CONTACTS
.
Aby poprosić o to uprawnienie, dodaj do pliku manifestu ten element podrzędny elementu
<manifest>
:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Skonfiguruj projekcję
W zależności od typu danych w wierszu może być widocznych tylko kilka kolumn lub wiele. Dodatkowo dane znajdują się w różnych kolumnach w zależności od ich typu.
Aby mieć pewność, że otrzymasz wszystkie możliwe kolumny dla wszystkich możliwych typów danych, musisz dodać do prognozy wszystkie nazwy kolumn. Zawsze pobieraj Data._ID
, jeśli wiążesz wynik Cursor
z ListView
. W przeciwnym razie powiązanie nie będzie działać. Pobierz również Data.MIMETYPE
, aby móc identyfikować typ danych w każdym pobieranym wierszu. Na przykład:
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 };
To odwzorowanie pobiera wszystkie kolumny wiersza w tabeli ContactsContract.Data
przy użyciu nazw kolumn zdefiniowanych w klasie ContactsContract.Data
.
Opcjonalnie możesz też użyć dowolnych innych stałych kolumn zdefiniowanych w klasie ContactsContract.Data
lub przez nią dziedziczonych. Zwróć jednak uwagę, że kolumny od SYNC1
do SYNC4
są przeznaczone dla adapterów synchronizacji, więc ich dane nie są przydatne.
Zdefiniuj kryteria wyboru
Zdefiniuj stałą klauzulę wyboru, tablicę do przechowywania argumentów wyboru i zmienną do przechowywania wartości wyboru. Znajdź kontakt w kolumnie Contacts.LOOKUP_KEY
. Na przykład:
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
Użycie symbolu zastępczego „?” w wyrażeniu tekstowym zaznaczenia gwarantuje, że wynik wyszukiwania będzie generowany przez powiązanie, a nie przez kompilację SQL. Takie podejście eliminuje możliwość wstrzyknięcia złośliwego kodu SQL.
Określanie kolejności sortowania
Określ kolejność sortowania w wyniku Cursor
. Aby wszystkie wiersze określonego typu danych były przechowywane razem, sortuj według kolumny Data.MIMETYPE
. Ten argument zapytania grupuje wszystkie wiersze e-maili razem, wszystkie wiersze z numerami telefonów itd. Na przykład:
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;
Uwaga: niektóre typy danych nie korzystają z podtypów, więc nie można według niego sortować danych.
Zamiast tego musisz iterować zwrócone dane Cursor
, określić typ danych bieżącego wiersza i przechowywać dane dla wierszy, które korzystają z podtypu. Po przeczytaniu kursora możesz posortować każdy typ danych według podtypu i wyświetlić wyniki.
Inicjowanie modułu wczytywania
Zawsze pobieraj dane od dostawcy kontaktów (i wszystkich innych dostawców treści) w wątku w tle. Do pobierania danych w tle używaj platformy Loader zdefiniowanej przez klasę LoaderManager
i interfejsu LoaderManager.LoaderCallbacks
.
Gdy wszystko będzie gotowe do pobrania wierszy, zainicjuj platformę ładowania, wywołując initLoader()
. Przekaż do metody identyfikator liczby całkowitej. Jest on przekazywany do metod LoaderManager.LoaderCallbacks
. Identyfikator pomaga używać wielu modułów wczytywania w aplikacji, umożliwiając ich rozróżnianie.
Ten fragment kodu pokazuje, jak zainicjować platformę ładowania:
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);
Implementacja onCreateLoader()
Zaimplementuj metodę onCreateLoader()
, która jest wywoływana przez platformę wczytywania natychmiast po wywołaniu initLoader()
. Zwracaj CursorLoader
z tej metody. Przeszukujesz tabelę ContactsContract.Data
, więc jako identyfikatora URI treści użyj stałej Data.CONTENT_URI
.
Na przykład:
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 ); }
Implementacja onLoadFinished() i onLoaderReset()
Zaimplementuj metodę onLoadFinished()
. Platforma ładowania wywołuje onLoadFinished()
, gdy dostawca kontaktów zwraca wyniki zapytania. Na przykład:
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; ... } }
Metoda onLoaderReset()
jest wywoływana, gdy platforma ładowania wykryje, że dane będące podstawą wyniku Cursor
uległy zmianie. Na tym etapie usuń wszelkie istniejące odwołania do funkcji Cursor
, ustawiając je na wartość null. Jeśli tego nie zrobisz, platforma ładowania nie zniszczy starego Cursor
i dojdzie do wycieku pamięci. Na przykład:
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; }
Pobieranie szczegółowych informacji o kontakcie
Pobieranie określonego typu danych kontaktu, np. wszystkich e-maili, odbywa się tak samo jak pobieranie wszystkich szczegółów. To jedyne zmiany, jakie musisz wprowadzić w kodzie wymienionym w sekcji Pobieranie wszystkich szczegółów kontaktu:
- Prognoza
- Zmodyfikuj prognozę, aby pobierać kolumny specyficzne dla tego typu danych. Zmodyfikuj też prognozę tak, aby używać stałych nazw kolumn zdefiniowanych w podklasie
ContactsContract.CommonDataKinds
odpowiadającej typowi danych. - Zaznaczenie
- Zmień tekst, aby wyszukać wartość
MIMETYPE
specyficzną dla Twojego typu danych. - Kolejność sortowania
- Wybierasz tylko jeden typ szczegółu, więc nie grupuj zwróconych danych
Cursor
wedługData.MIMETYPE
.
Opis tych modyfikacji znajduje się w kolejnych sekcjach.
Zdefiniuj rzut
Zdefiniuj kolumny, które chcesz pobrać, używając stałych nazw kolumn z podklasy ContactsContract.CommonDataKinds
jako typu danych.
Jeśli zamierzasz powiązać obiekt Cursor
z ListView
, pamiętaj, aby pobrać kolumnę _ID
. Aby na przykład pobrać dane poczty e-mail, określ to odwzorowanie:
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 };
Zwróć uwagę, że to odwzorowanie używa nazw kolumn zdefiniowanych w klasie ContactsContract.CommonDataKinds.Email
, a nie nazw kolumn zdefiniowanych w klasie ContactsContract.Data
. Używanie nazw kolumn typowych dla adresów e-mail zwiększa czytelność kodu.
W prognozie możesz też użyć dowolnej z pozostałych kolumn zdefiniowanych w podklasie ContactsContract.CommonDataKinds
.
Zdefiniuj kryteria wyboru
Zdefiniuj wyrażenie tekstowe, które będzie pobierać wiersze LOOKUP_KEY
określonego kontaktu i Data.MIMETYPE
wybranych szczegółów. Wartość MIMETYPE
umieść w pojedynczych cudzysłowach, dołączając znak „'
” (pojedynczy cudzysłów) na początku i na końcu stałej. W przeciwnym razie dostawca interpretuje stałą jako nazwę zmiennej, a nie wartość ciągu znaków. W przypadku tej wartości nie musisz używać symbolu zastępczego, ponieważ zamiast wartości podanej przez użytkownika używasz stałej wartości. Na przykład:
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 = { "" };
Definiowanie kolejności sortowania
Określ kolejność sortowania dla zwracanego elementu Cursor
. Pobierasz dane o konkretnym typie, więc pomiń sortowanie według zbioru danych MIMETYPE
.
Jeśli typ danych szczegółowych, które szukasz, zawiera podtyp, przeprowadź sortowanie według niego.
Na przykład w przypadku danych poczty e-mail możesz posortować je według kategorii Email.TYPE
:
Kotlin
private const val SORT_ORDER: String = "${Email.TYPE} ASC"
Java
private static final String SORT_ORDER = Email.TYPE + " ASC ";