W tej lekcji dowiesz się, jak pobierać szczegółowe dane kontaktowe, takie jak adresy e-mail czy numery telefonu. To szczegóły, na które zwracają uwagę użytkownicy pobierając kontakt. Możesz podać wszystkie szczegóły kontaktu lub wyświetlić tylko dane określonego typu. takich jak 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 dowiesz się, jak
pobrania 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 wykonuje domyślne złączenie tabeli ContactsContract.Contacts
z tabelą ContactsContract.Data
.
Opis kolumny LOOKUP_KEY
to więcej dowiesz się z lekcji Pobieranie nazw kontaktów.
Uwaga: pobieranie wszystkich szczegółów kontaktu zmniejsza wydajność urządzenia, ponieważ wymaga pobierania wszystkich kolumn z tabeli ContactsContract.Data
. Zanim użyjesz tej techniki, zastanów się nad wpływem na wydajność.
Prośba o przyznanie uprawnień
Aby można było odczytywać dane z dostawcy kontaktów, aplikacja musi mieć
Uprawnienie READ_CONTACTS
.
Aby poprosić o to uprawnienie, dodaj do pliku manifestu element podrzędny
<manifest>
:
<uses-permission android:name="android.permission.READ_CONTACTS" />
Konfigurowanie rzutowania
W zależności od typu danych zawartych w wierszu może on zawierać tylko kilka lub więcej kolumn. Ponadto
są w różnych kolumnach w zależności od typu danych.
Aby mieć pewność, że otrzymasz 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 poziomem ListView
. W przeciwnym razie powiązanie nie zadziała. Pobierz też Data.MIMETYPE
dzięki czemu możesz określić typ danych w każdym pobranym 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 prognozowanie pobiera wszystkie kolumny z wiersza w
ContactsContract.Data
z nazwami kolumn podanymi w
klasy 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 synchronizacji
więc dane z nich nie będą przydatne.
Definiowanie kryteriów wyboru
Zdefiniuj stałą klauzuli wyboru, tablicę do przechowywania argumentów wyboru oraz
do przechowywania wartości zaznaczenia. 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żywasz „?” jako symbolu zastępczego w wyrażeniu tekstowym zaznaczenia, gwarantuje, że wynik wyszukiwania jest generowany przez powiązanie, a nie przez kompilację SQL. Takie podejście eliminuje możliwość wstrzyknięcia złośliwego kodu SQL.
Definiowanie kolejności sortowania
Określ kolejność sortowania, która ma zostać użyta w wynikowym elemencie Cursor
. Aby
zachować wszystkie wiersze danego typu danych razem, posortuj według
Data.MIMETYPE
. Ten argument zapytania:
grupował wszystkie wiersze e-maili razem, wszystkie wiersze telefonów razem 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órych typów danych nie można sortować według podtypu.
Zamiast tego trzeba iterować zwrócony kod Cursor
,
określać typ danych bieżącego wiersza i przechowywać dane w wierszach, które korzystają z podtypu. Po zakończeniu odczytywania kursora możesz posortować każdy typ danych według podtypu i wyświetlić wyniki.
Inicjowanie procesu wczytywania
Zawsze pobieraj dane od dostawcy kontaktów (i od wszystkich innych dostawców treści) w wątku w tle. Użyj platformy wczytywania zdefiniowanej przez tag
LoaderManager
i
Interfejs LoaderManager.LoaderCallbacks
do wyświetlania w tle
dane.
Gdy wszystko będzie gotowe do pobrania wierszy, zainicjuj platformę wczytywania,
Dzwonię pod initLoader()
. Prześlij
identyfikator będący liczbą całkowitą; ten identyfikator jest przekazywany do
LoaderManager.LoaderCallbacks
metody. Identyfikator pomaga
korzysta z kilku ładunków w aplikacji, co pozwala je rozróżnić.
Ten fragment kodu pokazuje, jak zainicjować platformę wczytywania:
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()
Zwróć
CursorLoader
w przypadku tej metody. Ponieważ szukasz
w tabeli ContactsContract.Data
użyj stałej
Data.CONTENT_URI
jako identyfikator 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 tag
onLoadFinished()
. Platforma wczytywania wywołuje
onLoadFinished()
gdy dostawca kontaktów zwróci 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 wczytywania wykryje, że kopia zapasowa danych
Cursor
uległo zmianie. Na tym etapie usuń wszystkie istniejące pliki referencyjne
do Cursor
, ustawiając je na null. Jeśli tego nie zrobisz,
platforma nie zniszczy starej platformy Cursor
, a Ty otrzymasz
wyciek danych. 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, takiego jak wszystkie e-maile, przebiega według tego samego wzorca 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 parametru
typu danych. Zmodyfikuj też odwzorowanie, by używać stałych nazwy kolumny zdefiniowanych w
Podklasa
ContactsContract.CommonDataKinds
odpowiadająca funkcji typu danych. - Zaznaczenie
-
Zmień tekst zaznaczenia, aby wyszukać
Wartość
MIMETYPE
związana z: typ danych. - Kolejność sortowania
-
Wybierasz tylko jeden typ szczegółów, więc nie grupuj zwróconych informacji
Cursor
, autor:Data.MIMETYPE
.
Te zmiany są opisane w następnych sekcjach.
Definiowanie prognozy
Zdefiniuj kolumny, które chcesz pobrać, używając stałych nazw kolumn w podklasie
funkcji ContactsContract.CommonDataKinds
dla typu danych.
Jeśli planujesz powiązać Cursor
z ListView
, pamiętaj, aby pobrać kolumnę _ID
. Aby na przykład pobrać dane poczty e-mail, zdefiniuj
ta prognoza:
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 ta projekcja używa nazw kolumn zdefiniowanych w klasie ContactsContract.CommonDataKinds.Email
, a nie nazw kolumn zdefiniowanych w klasie ContactsContract.Data
. Korzystanie z nazw kolumn związanych z e-mailem ułatwia czytelność kodu.
W projekcji możesz też użyć dowolnej z innych kolumn zdefiniowanych w podklasie ContactsContract.CommonDataKinds
.
Definiowanie kryteriów wyboru
Zdefiniuj wyrażenie tekstowe wyszukiwania, które pobiera wiersze związane z określonym kontaktem
LOOKUP_KEY
oraz
Data.MIMETYPE
szczegółów
w pobliżu. 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. Dla tej wartości nie trzeba używać symbolu zastępczego, ponieważ
za pomocą stałej, 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
Określ kolejność sortowania dla zwróconych elementów Cursor
. Ponieważ pobierasz określony typ danych, pomiń sortowanie według kolumny 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 ";