W tej lekcji dowiesz się, jak pobierać szczegółowe dane kontaktowe, takie jak adresy e-mail czy numery telefonu. To są informacje, których użytkownicy szukają, gdy pobierają kontakt. Możesz podać wszystkie informacje o kontakcie lub tylko dane określonego typu, na przykład adresy e-mail.
W tej lekcji zakładamy, że masz już wiersz ContactsContract.Contacts
z kontaktem wybranym przez użytkownika.
W lekcji Pobieranie nazw kontaktów znajdziesz informacje o pobieraniu listy kontaktów.
Pobieranie wszystkich szczegółów kontaktu
Aby pobrać wszystkie szczegóły kontaktu, wyszukaj w tabeli
ContactsContract.Data
wiersze zawierające adres
LOOKUP_KEY
tego kontaktu. Ta kolumna jest dostępna w tabeli ContactsContract.Data
, ponieważ dostawca danych Kontakty tworzy domyślne złączenie między tabelą ContactsContract.Contacts
a tabelą ContactsContract.Data
. Kolumna LOOKUP_KEY
została szczegółowo omówiona w lekcji Pobieranie nazw kontaktów.
Uwaga: pobranie wszystkich szczegółów kontaktu zmniejsza wydajność urządzenia, ponieważ musi ono pobrać wszystkie kolumny w tabeli ContactsContract.Data
. Zanim użyjesz tej metody, weź pod uwagę wpływ na wydajność.
Prośba o uprawnienia
Aby odczytywać dane od dostawcy kontaktów, aplikacja musi mieć uprawnienie READ_CONTACTS
.
Aby poprosić o to uprawnienie, dodaj do pliku manifestu ten element podrzędny
<manifest>
:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Konfigurowanie prognozy
W zależności od typu danych wiersz może używać tylko kilku kolumn lub wielu. Poza tym dane są w różnych kolumnach w zależności od ich typu.
Aby mieć pewność, że otrzymujesz wszystkie możliwe kolumny dla wszystkich możliwych typów danych, musisz dodać do projekcji wszystkie nazwy kolumn. Zawsze pobieraj dane z poziomu Data._ID
, jeśli chcesz związać wynik Cursor
z poziomu ListView
. W przeciwnym razie powiązanie nie zadziała. Pobierz też Data.MIMETYPE
, aby określić typ danych każdego pobieranego wiersza. 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 prognozowanie pobiera wszystkie kolumny w wierszu w tabeli ContactsContract.Data
przy użyciu nazw kolumn zdefiniowanych w klasie ContactsContract.Data
.
Opcjonalnie możesz też użyć dowolnych innych stałych kolumny zdefiniowanych w klasie ContactsContract.Data
lub odziedziczonych przez nią. Zwróć jednak uwagę, że kolumny od SYNC1
do SYNC4
są przeznaczone do użycia przez adaptery synchronizacji, więc zawarte w nich dane nie są przydatne.
Definiowanie kryteriów wyboru
Zdefiniuj stałą dla klauzuli selekcji, tablicę na argumenty selekcji i zmienną na wartość selekcji. Aby znaleźć kontakt, użyj kolumny 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 znaku „?” jako zastępnika w wyrażeniu tekstowym selekcji zapewnia, że wynik wyszukiwania będzie generowany przez wiązanie, a nie kompilację SQL. Takie podejście eliminuje możliwość wstrzyknięcia złośliwego kodu SQL.
Definiowanie kolejności sortowania
Określ kolejność sortowania w wynikającym z tego wierszu Cursor
. Aby
zachować wszystkie wiersze danego typu danych razem, posortuj według
Data.MIMETYPE
. Ten argument zapytania grupuje wszystkie wiersze e-maili razem, wszystkie wiersze numerów 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 używają podtypu, więc nie można sortować według podtypu.
Zamiast tego musisz przejść przez zwrócone Cursor
, określić typ danych bieżącego wiersza i zapisać dane w przypadku wierszy, które używają podtypu. Po zakończeniu odczytywania kursora możesz posortować każdy typ danych według podtypu i wyświetlić wyniki.
Inicjowanie ładowarki
Zawsze pobieraj dane od dostawcy kontaktów (i od wszystkich innych dostawców treści) w wątku w tle. Do pobierania w tle możesz używać mechanizmu ładowania zdefiniowanego przez klasę LoaderManager
i interfejs LoaderManager.LoaderCallbacks
.
Gdy wszystko będzie gotowe do pobrania wierszy, zainicjuj framework ładowarki, wywołując funkcję initLoader()
. Przekaż do metody identyfikator liczby całkowitej; ten identyfikator jest przekazywany do metod LoaderManager.LoaderCallbacks
. Identyfikator ułatwia korzystanie z kilku ładowarek w aplikacji, ponieważ pozwala je od siebie odróżnić.
Ten fragment kodu pokazuje, jak zainicjować framework loadera:
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 metody onCreateLoader()
Zaimplementuj metodę onCreateLoader()
, która jest wywoływana przez platformę ładowania zaraz po wywołaniu initLoader()
. Zwracaj wartośćCursorLoader
z tej metody. Ponieważ szukasz w tabeli ContactsContract.Data
, użyj stałej Data.CONTENT_URI
jako identyfikatora URI treści.
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 ); }
Zaimplementuj metody onLoadFinished() i onLoaderReset().
Zaimplementuj metodę onLoadFinished()
. Gdy dostawca kontaktów zwróci wyniki zapytania, framework loader wywołuje funkcję onLoadFinished()
. 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 mechanizm ładowarki wykryje, że dane stanowiące podstawę wyniku
Cursor
uległy zmianie. W tym momencie usuń wszystkie istniejące odwołania do Cursor
, ustawiając je na null. Jeśli tego nie zrobisz, framework ładowarki 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 o kontakcie, np. wszystkich e-maili, odbywa się w taki sam sposób jak pobieranie wszystkich szczegółów. Oto jedyne zmiany, które musisz wprowadzić w kodzie wymienionym w sekcji Pobieranie wszystkich szczegółów kontaktu:
- Prognoza
- Zmodyfikuj prognozę, aby pobrać kolumny właściwe dla danego typu danych. Zmodyfikuj też rzutowanie, aby używać stałych nazw kolumny zdefiniowanych w podklasie
ContactsContract.CommonDataKinds
odpowiadającej typowi danych. - Zaznaczenie
- Zmodyfikuj tekst zaznaczenia, aby wyszukać wartość
MIMETYPE
, która jest odpowiednia dla Twojego typu danych. - Kolejność sortowania
- Ponieważ wybierasz tylko jeden typ szczegółów, nie grupowaj zwracanych danych
Cursor
wedługData.MIMETYPE
.
Te zmiany są opisane w następnych sekcjach.
Definiowanie projekcji
Zdefiniuj kolumny, które chcesz pobrać, używając stałych nazw kolumn z podklasy ContactsContract.CommonDataKinds
jako typu danych.
Jeśli planujesz powiązać Cursor
z ListView
, pamiętaj, aby pobrać kolumnę _ID
. Aby na przykład pobrać dane e-maila, zdefiniuj tę projekcję:
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 w tym prognozie używane są nazwy kolumn zdefiniowane w klasie ContactsContract.CommonDataKinds.Email
, a nie nazwy kolumn zdefiniowane w klasie ContactsContract.Data
. Użycie nazw kolumn dotyczących adresu e-mail zwiększa czytelność kodu.
W projekcji możesz też używać dowolnych innych kolumn zdefiniowanych w podklasie ContactsContract.CommonDataKinds
.
Definiowanie kryteriów wyboru
Zdefiniuj wyrażenie wyszukiwania tekstowego, które pobiera wiersze dotyczące konkretnego kontaktu LOOKUP_KEY
i Data.MIMETYPE
odpowiednich szczegółów. Otocz wartość MIMETYPE
pojedynczymi cudzysłowami, łącząc znak „'
” (pojedyncze cudzysłowy) na początku i na końcu stałej. W przeciwnym razie dostawca zinterpretuje stałą jako nazwę zmiennej, a nie jako ciąg znaków. Nie musisz używać symbolu zastępczego dla tej wartości, ponieważ używasz stałej wartości, a nie wartości podanej przez użytkownika. 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
Zdefiniuj kolejność sortowania zwróconych wartości Cursor
. Pobierasz określony typ danych, więc pomiń sortowanie w polu MIMETYPE
.
Jeśli jednak typ danych, którego szukasz, zawiera podtyp, możesz posortować dane według niego.
Na przykład w przypadku danych e-mail możesz sortować według tych kolumn:Email.TYPE
:
Kotlin
private const val SORT_ORDER: String = "${Email.TYPE} ASC"
Java
private static final String SORT_ORDER = Email.TYPE + " ASC ";