Pobieranie szczegółów kontaktu

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ć CursorListView, 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 ";