Dostawca kontaktów to zaawansowany i elastyczny komponent Androida, który zarządza czyli centralnego repozytorium danych o ludziach. Dostawca kontaktów jest źródłem danych widocznych w aplikacji do obsługi kontaktów na urządzeniu. Dostęp do tych danych możesz również uzyskać w swoich aplikacji oraz przesyłania danych między urządzeniem a usługami online. Dostawca obsługuje wiele źródeł danych i stara się zarządzać jak największą liczbą danych o każdej osobie, co powoduje, że jego organizacja jest skomplikowana. Dlatego interfejs API dostawcy zawiera obszerny zbiór klas i interfejsów umów, które ułatwiają zarówno pobieranie, jak i modyfikowanie danych.
Tematy w tym przewodniku:
- Podstawowa struktura dostawcy.
- Jak pobrać dane od dostawcy.
- Jak zmodyfikować dane u dostawcy.
- Jak napisać adapter synchronizacji do synchronizowania danych z serwera z usługą Contacts Provider.
W tym przewodniku przyjęto założenie, że znasz podstawy dotyczące dostawców treści na Androida. Aby dowiedzieć się więcej o dostawcach treści na Androida, przeczytaj przewodnik Podstawy dotyczące dostawców treści.
Organizacja dostawcy kontaktów
Dostawca kontaktów to komponent dostawcy treści na Androida. Uwzględnione są 3 rodzaje danych: dane o osobie, z których każdy odpowiada tabeli oferowanej przez dostawcę, przedstawione na rys. 1:

Rysunek 1. Struktura tabeli dostawcy kontaktów
Te 3 tabele zwykle nazywane są nazwami klas umów. Zajęcia zdefiniuj stałe dla identyfikatorów URI treści, nazw kolumn i wartości kolumn używanych w tabelach:
-
Tabela
ContactsContract.Contacts
- Wiersze reprezentujące różne osoby na podstawie zagregowanych wierszy nieprzetworzonych kontaktów.
-
ContactsContract.RawContacts
tabela - Wiersze zawierające podsumowanie danych osoby, które są specyficzne dla typu i konta użytkownika.
-
ContactsContract.Data
tabela - Wiersze zawierające szczegóły nieprzetworzonego kontaktu, takie jak adresy e-mail czy numery telefonów.
Pozostałe tabele reprezentowane przez klasy kontraktu w ContactsContract
to tabele pomocnicze, których dostawca kontaktów używa do zarządzania operacjami lub obsługi określonych funkcji w aplikacji kontaktów lub telefonii na urządzeniu.
Nieprzetworzone kontakty
Dane kontaktowe w postaci nieprzetworzonych danych to informacje o osobach pochodzące z jednego typu konta i jego nazwy. Dostawca kontaktów zezwala na więcej niż jedną usługę online jako źródło dotyczące osoby, dostawca kontaktów umożliwia wiele nieprzetworzonych kontaktów tej samej osoby. Wiele nieprzetworzonych kontaktów pozwala także łączyć dane danej osoby z więcej niż jednego konta. z konta tego samego rodzaju.
Większość danych nieprzetworzonych kontaktów jest przechowywana w
Tabela ContactsContract.RawContacts
. Są one przechowywane w co najmniej jednym
wiersze w tabeli ContactsContract.Data
. Każdy wiersz danych zawiera kolumnę
Data.RAW_CONTACT_ID
, które
zawiera wartość RawContacts._ID
swojego elementu
nadrzędny wiersz ContactsContract.RawContacts
.
Ważne kolumny kontaktów w postaci nieprzetworzonych danych
Ważne kolumny w tabeli ContactsContract.RawContacts
są wymienione w tabeli 1. Po tabeli przeczytaj te uwagi:
Tabela 1. Ważne nieprzetworzone kolumny kontaktów.
Nazwa kolumny | Użyj | Uwagi |
---|---|---|
ACCOUNT_NAME
|
Nazwa konta rodzaju konta, które jest źródłem tego nieprzetworzonego kontaktu.
Na przykład nazwa konta Google to jedno z kont Gmail właściciela urządzenia
adresów. Więcej informacji znajdziesz w następnym wpisie dotyczącym ACCOUNT_TYPE .
|
Format tej nazwy zależy od typu konta. Nie zawsze jest to adres e-mail. |
ACCOUNT_TYPE
|
Rodzaj konta, który jest źródłem tego nieprzetworzonego kontaktu. Na przykład typ konta Google to com.google . Zawsze określaj typ konta za pomocą identyfikatora domeny, której jesteś właścicielem lub którą kontrolujesz. Dzięki temu Twoje reklamy
jest niepowtarzalny.
|
Typ konta, który oferuje dane kontaktów, ma zwykle powiązany adapter synchronizacji, jest synchronizowane z dostawcą kontaktów. |
DELETED
|
Flaga „deleted” (usunięty) w przypadku nieprzetworzonego kontaktu. | Ten parametr pozwala dostawcy kontaktów na utrzymywanie wiersza wewnętrznie, dopóki adaptery synchronizacji będą mogły usunąć go ze swoich serwerów, a następnie z repozytorium. |
Uwagi
Oto ważne uwagi na temat
Tabela ContactsContract.RawContacts
:
-
Nieprzetworzona nazwa kontaktu nie jest przechowywana w wierszu w
ContactsContract.RawContacts
Zamiast tego jest przechowywany w tabeliContactsContract.Data
, w wierszuContactsContract.CommonDataKinds.StructuredName
. Nieprzetworzony kontakt ma tylko 1 wiersz tego typu w tabeliContactsContract.Data
. -
Uwaga: aby użyć w wierszu nieprzetworzonego kontaktu danych z konta, należy
zarejestrować się w
AccountManager
. Aby to zrobić, poproś użytkowników o dodanie typu konta i jego nazwy do listy kont. Jeśli tego nie zrobisz, dostawca kontaktów automatycznie usunie wiersz z kontaktem.Jeśli np. chcesz, aby aplikacja przechowywała dane kontaktów w usłudze internetowej z domeną
com.example.dataservice
, a konto użytkownika w tej usłudze tobecky.sharp@dataservice.example.com
, użytkownik musi najpierw dodać „typ” konta (com.example.dataservice
) i „nazwa” konta (becky.smart@dataservice.example.com
), zanim aplikacja będzie mogła dodawać nieprzetworzone wiersze kontaktów. Możesz wyjaśnić to wymaganie w dokumentacji lub poprosić użytkownika o dodanie typu i nazwy. Typy kont i ich nazwy są opisane bardziej szczegółowo w następnej sekcji.
Źródła nieprzetworzonych danych kontaktów
Aby zrozumieć, jak działają kontakty w postaci surowych danych, zastanów się nad użytkownikiem „Emilią Dickinson”, która ma na swoim urządzeniu zdefiniowane 3 konta użytkowników:
emily.dickinson@gmail.com
emilyd@gmail.com
- Konto na Twitterze „belle_of_amherst”
Ten użytkownik ma włączoną opcję Synchronizuj kontakty na wszystkich 3 kontach w ustawieniach Konta.
Załóżmy, że Emily Dickinson otwiera okno przeglądarki, loguje się w Gmailu jako emily.dickinson@gmail.com
, otwiera Kontakty i dodaje „Thomas Higginson”. Później loguje się w Gmailu jako
emilyd@gmail.com
i wysyła e-maila do „Thomasa Higginsona”, który automatycznie
dodaje go do kontaktów. Obserwuje też na Twitterze konto „colonel_tom” (identyfikator Thomasa Higginsona).
W wyniku tej pracy dostawca kontaktów tworzy 3 nieprzetworzone kontakty:
-
Nowy kontakt „Thomas Higginson” powiązane z adresem
emily.dickinson@gmail.com
. Typ konta użytkownika to Google. -
Drugi kontakt w postaci tekstu zwykłego dla „Thomas Higginson”, powiązany z
emilyd@gmail.com
. Typ konta użytkownika to również Google. Na koncie Google jest drugi nieprzetworzony kontakt, mimo że jego nazwa jest identyczna z poprzednią, ponieważ ta osoba została dodana do innego konta użytkownika. - Trzeci kontakt w formie tekstu dotyczący „Thomasa Higginsona” powiązany z „belle_of_amherst”. Typ konta użytkownika to Twitter.
Dane
Jak już wspomnieliśmy, dane nieprzetworzonego kontaktu są przechowywane w wierszu ContactsContract.Data
, który jest powiązany z wartością _ID
nieprzetworzonego kontaktu. Dzięki temu pojedynczy nieprzetworzony kontakt może zawierać wiele wystąpień tego samego typu danych, np. adresów e-mail lub numerów telefonów. Jeśli na przykład „Thomas Higginson” (nieprzetworzony wiersz kontaktu powiązany z kontem Google emilyd@gmail.com
) ma adres e-mail domowy thigg@gmail.com
i adres e-mail służbowy thomas.higginson@gmail.com
, dostawca kontaktów przechowuje te 2 wiersze adresów e-mail i połącza je z nieprzetworzonym kontaktem.
Zwróć uwagę, że w tej jednej tabeli są przechowywane różne typy danych. W tabeli ContactsContract.Data
znajdują się wiersze z danymi o nazwie wyświetlanej, numerze telefonu, adresie e-mail, adresie pocztowym, zdjęciu i witrynie. Aby ułatwić sobie to zadanie,
Tabela ContactsContract.Data
zawiera kolumny z opisowymi nazwami,
i inne, używając nazw ogólnych. Zawartość kolumny z nazwami opisowymi ma takie samo znaczenie
niezależnie od typu danych w wierszu, a zawartość kolumny z nazwą ogólną
znaczenia w zależności od typu danych.
Nazwa kolumny powinna być zwięzła i opisowa.
Oto kilka przykładów opisowych nazw kolumn:
-
RAW_CONTACT_ID
- Wartość kolumny
_ID
w kontakcie nieprzetworzonym dla tych danych. -
MIMETYPE
- Typ danych przechowywanych w tym wierszu, wyrażony jako niestandardowy typ MIME. Dostawca kontaktów używa typów MIME zdefiniowanych w podklasach
ContactsContract.CommonDataKinds
. Te typy MIME są typu open source i mogą być używane przez dowolną aplikację lub adapter synchronizacji współpracujący z usługą dostawcy kontaktów. -
IS_PRIMARY
-
Jeśli ten typ wiersza danych może wystąpić więcej niż jeden raz w przypadku nieprzetworzonego kontaktu,
Flagi kolumn:
IS_PRIMARY
wiersz danych, który zawiera dane podstawowe dla danego typu. Jeśli na przykład użytkownik naciśnie i przytrzyma numer telefonu kontaktu, a następnie wybierze Ustaw domyślny, kolumnaIS_PRIMARY
w wierszuContactsContract.Data
zawierającym ten numer będzie miała wartość różną od 0.
Ogólne nazwy kolumn
Jest 15 kolumn ogólnych o nazwach od DATA1
do
DATA15
, które są ogólnie dostępne, oraz 4 dodatkowe, ogólne
kolumn od SYNC1
do SYNC4
, które powinny być używane tylko przez synchronizację
i ładowarki. Stałe nazwy kolumn działają zawsze, niezależnie od typu danych zawartych we wierszu.
Kolumna DATA1
została zindeksowana. Dostawca kontaktów zawsze używa tej kolumny do danych, które według niego będą najczęściej docelowymi elementami zapytania. Przykład:
w wierszu e-mail, ta kolumna zawiera rzeczywisty adres e-mail.
Zgodnie z konwencją kolumna DATA15
jest zarezerwowana do przechowywania dużych obiektów binarnych
(BLOB), np. miniatur zdjęć.
Nazwy kolumn związane z konkretnymi typami
Aby ułatwić pracę z kolumnami w przypadku danego typu wiersza, usługa Contacts Provider udostępnia też nazwy kolumn zależne od typu, zdefiniowane w podklasach klasy ContactsContract.CommonDataKinds
. Stałe dają po prostu
inną nazwę stałą z tą samą nazwą kolumny, co ułatwia dostęp do danych w wierszu
określonego typu.
Na przykład klasa ContactsContract.CommonDataKinds.Email
definiuje stałe nazw kolumn dla wiersza ContactsContract.Data
o typie MIME Email.CONTENT_ITEM_TYPE
. Klasa zawiera stałą wartość ADDRESS
w kolumnie adresu e-mail. Rzeczywista wartość
ADDRESS
to „data1”, czyli
taka sama jak ogólna nazwa kolumny.
Uwaga: nie dodawaj własnych danych niestandardowych do pola
ContactsContract.Data
w tabeli używającej wiersza, który zawiera jeden z
ze wstępnie zdefiniowanych typów MIME. Jeśli to zrobisz, możesz utracić dane lub spowodować, że dostawca
wadliwego działania. Nie należy na przykład dodawać wiersza z typem MIMEEmail.CONTENT_ITEM_TYPE
, który zawiera nazwę użytkownika zamiast adresu e-mail w kolumnie DATA1
. Jeśli w przypadku wiersza używasz własnego niestandardowego typu MIME, możesz dowolnie definiować nazwy kolumn dla tego typu i z nich korzystać.
Rysunek 2 pokazuje, jak kolumny opisowe i kolumny danych wyglądają w wierszu ContactsContract.Data
oraz jak nazwy kolumn dla poszczególnych typów „nakładają się” na nazwy ogólne kolumn.

Rysunek 2. Nazwy kolumn typowe dla danego typu i ogólne nazwy kolumn.
Klasy nazw kolumn zależne od typu
Tabela 2 zawiera listę najczęściej używanych klas nazw kolumn dla poszczególnych typów:
Tabela 2. Klasy nazw kolumn zależne od typu
Klasa mapowania | Typ danych | Uwagi |
---|---|---|
ContactsContract.CommonDataKinds.StructuredName |
Dane nazwy nieprzetworzonego kontaktu powiązanego z tym wierszem danych. | Nieprzetworzony kontakt ma tylko jeden z tych wierszy. |
ContactsContract.CommonDataKinds.Photo |
Główne zdjęcie nieprzetworzonego kontaktu powiązanego z tym wierszem danych. | Nieprzetworzony kontakt ma tylko 1 z tych wierszy. |
ContactsContract.CommonDataKinds.Email |
Adres e-mail nieprzetworzonego kontaktu powiązanego z tym wierszem danych. | Nieprzetworzony kontakt może mieć kilka adresów e-mail. |
ContactsContract.CommonDataKinds.StructuredPostal |
Adres pocztowy nieprzetworzonego kontaktu powiązanego z tym wierszem danych. | Kontakt w postaci surowych danych może mieć wiele adresów pocztowych. |
ContactsContract.CommonDataKinds.GroupMembership |
Identyfikator, który łączy surowy kontakt z jedną z grup w dostawcy kontaktów. | Grupy to opcjonalna funkcja związana z rodzajem konta i nazwą konta. Ich opis znajdziesz tutaj: Więcej informacji znajdziesz w sekcji Grupy kontaktów. |
kontakty,
Dostawca kontaktów łączy wiersze nieprzetworzonych kontaktów we wszystkich typach kont i nazwach kont, aby utworzyć kontakt. Ułatwia to wyświetlanie i modyfikowanie wszystkich danych zebrane przez użytkownika dla danej osoby. Dostawca danych kontaktów zarządza tworzeniem nowych wierszy kontaktów oraz agregacją nieprzetworzonych kontaktów z istniejącym wierszem kontaktu. Ani aplikacje, ani adaptery synchronizacji nie mogą dodawać kontaktów, a niektóre kolumny w wierszu kontaktu są tylko do odczytu.
Uwaga: jeśli spróbujesz dodać kontakt do dostawcy kontaktów z wartością insert()
, otrzymasz wyjątek UnsupportedOperationException
. Jeśli próbujesz zaktualizować kolumnę
który jest oznaczony jako „tylko do odczytu”, aktualizacja jest ignorowana.
Dostawca kontaktów tworzy nowy kontakt w odpowiedzi na dodanie nowego nieprzetworzonego kontaktu. który nie pasuje do żadnych istniejących kontaktów. Robi to również, jeśli istniejący nieprzetworzony dane kontaktu zmienią się w taki sposób, że nie będą już zgodne z kontaktem, do którego został przypisany wcześniej podłączone. Jeśli aplikacja lub adapter synchronizacji tworzy nowy nieprzetworzony kontakt, pasuje do istniejącego kontaktu, nowy nieprzetworzony kontakt jest agregowany z istniejącym kontakt.
Dostawca kontaktów łączy wiersz kontaktu z nieprzetworzonymi wierszami kontaktów z wierszami kontaktów
_ID
kolumna w Contacts
tabeli. Kolumna CONTACT_ID
w tabeli nieprzetworzonych kontaktów
ContactsContract.RawContacts
zawiera _ID
wartości dla:
w wierszu kontaktów powiązanym z każdym wierszem nieprzetworzonych kontaktów.
Tabela ContactsContract.Contacts
zawiera też kolumnę
LOOKUP_KEY
to
„trwały” do wiersza kontaktu. Ponieważ dostawca kontaktów przechowuje kontakty
automatycznie, może to zmienić wartość _ID
w wierszu kontaktu
w odpowiedzi na agregację lub synchronizację. Nawet jeśli tak się stanie, identyfikator URI treści
CONTENT_LOOKUP_URI
w połączeniu z
LOOKUP_KEY
kontaktu wciąż będzie
najedź na wiersz kontaktu, dzięki czemu możesz
LOOKUP_KEY
aby zachować linki do sekcji „Ulubione”, kontakty itd. Ta kolumna ma własny format:
nie ma związku z formatem kolumny _ID
.
Rysunek 3 pokazuje relacje między 3 głównymi tabelami.

Rysunek 3. Relacje między tabelami Kontakty, Nieprzetworzone kontakty i Szczegóły.
Uwaga: jeśli publikujesz aplikację w Sklepie Google Play lub jeśli Twoja aplikacja jest na urządzeniu z Androidem w wersji 10 (poziom interfejsu API 29) lub nowszej, pamiętaj, że ograniczony zestaw pól danych i metod dotyczących kontaktów jest przestarzały.
Po spełnieniu określonych warunków system okresowo usuwa wszystkie wartości. zapisane w tych polach danych:
-
ContactsContract.ContactOptionsColumns.LAST_TIME_CONTACTED
-
ContactsContract.ContactOptionsColumns.TIMES_CONTACTED
-
ContactsContract.DataUsageStatColumns.LAST_TIME_USED
-
ContactsContract.DataUsageStatColumns.TIMES_USED
Interfejsy API używane do ustawiania powyższych pól danych również są nieaktualne:
Ponadto poniższe pola nie zwracają już częstych kontaktów. Notatka że niektóre z tych pól wpływają na ranking kontaktów tylko wtedy, gdy są częścią określonej danych rodzaj.
-
ContactsContract.Contacts.CONTENT_FREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_FILTER_URI
-
CONTENT_FILTER_URI
(dotyczy tylko E-mail, Telefon, Możliwość połączenia, oraz Osoby kontaktowe rodzaje danych) -
ENTERPRISE_CONTENT_FILTER_URI
(dotyczy tylko typów danych Email, Phone i Callable)
Jeśli aplikacje uzyskują dostęp do tych pól lub interfejsów API albo je aktualizują, użyj alternatywnych metod. Na przykład w pewnych przypadkach możesz korzystać z prywatnych dostawców treści lub innych danych przechowywanych w aplikacji lub systemach zaplecza.
Aby sprawdzić, czy ta zmiana nie ma wpływu na działanie aplikacji, możesz ręcznie wyczyścić te pola danych. Aby to zrobić, uruchom to polecenie ADB na urządzeniu z Androidem 4.1 (poziom interfejsu API 16) lub nowszym:
adb shell content delete \ --uri content://com.android.contacts/contacts/delete_usage
Dane z adapterów synchronizacji
Użytkownicy wpisują dane kontaktów bezpośrednio na urządzeniu, ale dane są też przesyłane do dostawcy kontaktów z usług internetowych za pomocą adapterów synchronizacji, które automatyzują przesyłanie danych między urządzeniem a usługami. Adaptery synchronizacji działają w tle pod kontrolą systemu i wywołują metody ContentResolver
, aby zarządzać danymi.
W Androidzie usługa internetowa współpracująca z adapterem synchronizacji jest określana na podstawie typu konta. Każdy adapter synchronizacji działa z jednym typem konta, ale może obsługiwać wiele nazw kont tego typu. W tej sekcji opisano pokrótce typy i nazwy kont Źródła nieprzetworzonych danych kontaktów. Definicje poniżej zawierają więcej szczegółów i omawiają, jak typ i nazwa konta wiążą się z adapterami i usługami synchronizacji.
- Rodzaj konta
-
Identyfikuje usługę, w której użytkownik przechowuje dane. W większości przypadków użytkownik musi uwierzytelnić się w usłudze. Dotyczy to na przykład Kontaktów Google
kodem
google.com
. Ta wartość odpowiada typowi konta używanego przez elementAccountManager
. - Nazwa konta
- Określa konkretne konto lub dane logowania do danego typu konta. Kontakty Google to te same konta co konta Google, które mają adres e-mail jako nazwę konta. Inne usługi mogą używać jednowyrazowej nazwy użytkownika lub identyfikatora liczbowego.
Rodzaje kont nie muszą być unikalne. Użytkownik może skonfigurować wiele kont Kontaktów Google i pobierać swoje dane do dostawcy kontaktów; może się tak zdarzyć, jeśli użytkownik ma jeden zestaw kontaktów osobistych na potrzeby nazwy konta osobistego i innego w zestawie służbowym. Nazwy kont to zazwyczaj unikalne. Razem określają konkretny przepływ danych między dostawcą kontaktów a usługą zewnętrzną.
Jeśli chcesz przenieść dane usługi do dostawcy kontaktów, musisz napisać lub sterownika. Szczegółowe informacje na ten temat znajdziesz w sekcji Adaptery synchronizacji dostawcy kontaktów.
Rysunek 4 przedstawia sposób, w jaki dostawca kontaktów wpisuje się w przepływ danych na temat ludzi. W polu „Synchroniz adaptery” każdy adapter jest oznaczony typem konta.

Rysunek 4. Przepływ danych dostawcy kontaktów.
Wymagane uprawnienia
Aplikacje, które chcą uzyskać dostęp do dostawcy kontaktów, muszą poprosić o te uprawnienia:
- Dostęp z możliwością odczytu do co najmniej 1 tabeli
-
READ_CONTACTS
, określony wAndroidManifest.xml
za pomocą elementu<uses-permission>
:<uses-permission android:name="android.permission.READ_CONTACTS">
. - Dostęp z możliwością zapisu do co najmniej 1 tabeli
-
WRITE_CONTACTS
, określony wAndroidManifest.xml
z<uses-permission>
element jako<uses-permission android:name="android.permission.WRITE_CONTACTS">
.
Te uprawnienia nie obejmują danych profilowych użytkownika. Profil użytkownika i wymagane uprawnienia są omawiane w następującej sekcji: Profil użytkownika.
Pamiętaj, że dane kontaktów użytkownika są osobiste i poufne. Użytkownicy niepokoją się ich prywatność, aby aplikacje nie gromadziły danych o nich i ich kontaktach. Jeśli nie będzie jasne, dlaczego potrzebujesz uprawnień do dostępu do danych kontaktów, użytkownicy mogą przyznać Twojej aplikacji niskie oceny lub po prostu odmówić jej zainstalowania.
Profil użytkownika
Tabela ContactsContract.Contacts
zawiera 1 wiersz z danymi profilu użytkownika urządzenia. Te dane opisują funkcję user
na urządzeniu, a nie
niż jeden z kontaktów użytkownika. Wiersz kontaktów profilu jest powiązany z wierszem kontaktów w postaci nieprzetworzonych danych w przypadku każdego systemu, który używa profilu.
Każdy wiersz nieprzetworzonych kontaktów profilu może mieć wiele wierszy danych. Stałe dostępu do użytkownika
profile są dostępne w zajęciach ContactsContract.Profile
.
Dostęp do profilu użytkownika wymaga specjalnych uprawnień. Oprócz
READ_CONTACTS
i
Do odczytu, zapisu i dostępu potrzebne są uprawnienia WRITE_CONTACTS
wymaga uprawnień android.Manifest.permission#READ_PROFILE i
uprawnienia android.Manifest.permission#WRITE_PROFILE do odczytu i zapisu,
.
Pamiętaj, że profil użytkownika należy uznać za poufny. Uprawnienie android.Manifest.permission#READ_PROFILE umożliwia dostęp do danych użytkownika urządzenia umożliwiających identyfikację tożsamości. Poinformuj użytkownika, dlaczego musisz mieć uprawnienia dostępu do profilu użytkownika w opisie aplikacji,
Aby pobrać wiersz kontaktu zawierający profil użytkownika,
Zadzwoń pod numer ContentResolver.query()
. Ustaw identyfikator URI treści na
CONTENT_URI
i nie podawaj żadnych
kryteria wyboru. Możesz też użyć tego identyfikatora URI treści jako podstawowego identyfikatora URI do pobierania nieprzetworzonych danych
kontaktów ani danych w profilu. Ten fragment kodu zwraca na przykład dane profilu:
Kotlin
// Sets the columns to retrieve for the user profile projection = arrayOf( ContactsContract.Profile._ID, ContactsContract.Profile.DISPLAY_NAME_PRIMARY, ContactsContract.Profile.LOOKUP_KEY, ContactsContract.Profile.PHOTO_THUMBNAIL_URI ) // Retrieves the profile from the Contacts Provider profileCursor = contentResolver.query( ContactsContract.Profile.CONTENT_URI, projection, null, null, null )
Java
// Sets the columns to retrieve for the user profile projection = new String[] { Profile._ID, Profile.DISPLAY_NAME_PRIMARY, Profile.LOOKUP_KEY, Profile.PHOTO_THUMBNAIL_URI }; // Retrieves the profile from the Contacts Provider profileCursor = getContentResolver().query( Profile.CONTENT_URI, projection , null, null, null);
Uwaga: jeśli pobierasz wiele wierszy kontaktów i chcesz sprawdzić, czy jeden z nich jest profilem użytkownika, przetestuj kolumnę IS_USER_PROFILE
wiersza. Ta kolumna ma wartość 1, jeśli kontakt to profil użytkownika.
Metadane dostawcy kontaktów
Dostawca kontaktów zarządza danymi, które śledzą stan danych kontaktów w archiwum. Te metadane repozytorium są przechowywane w różnych miejscach, takich jak
wiersze tabeli Nieprzetworzone kontakty, dane i kontakty,
ContactsContract.Settings
oraz
Tabela ContactsContract.SyncState
. Tabela poniżej zawiera
wpływ każdego z tych elementów metadanych:
Tabela 3. Metadane w dostawcy kontaktów
Tabela | Kolumna | Wartości | Znaczenie |
---|---|---|---|
ContactsContract.RawContacts |
DIRTY |
„0” – nie zmieniono od ostatniej synchronizacji. |
Oznacza nieprzetworzone kontakty, które zostały zmienione na urządzeniu i muszą zostać zsynchronizowane z
serwera. Wartość jest ustawiana automatycznie przez dostawcę kontaktów, gdy aplikacje na Androida aktualizują wiersz.
Adaptery synchronizacji, które modyfikują kontakty lub tabele danych, powinny zawsze dołączać parametr
ciąg |
„1” – zmienione od ostatniej synchronizacji, wymaga synchronizacji z powrotem na serwer. | |||
ContactsContract.RawContacts |
VERSION |
Numer wersji danego wiersza. | Dostawca kontaktów automatycznie zwiększa tę wartość za każdym razem, gdy wiersz lub zmian w powiązanych danych. |
ContactsContract.Data |
DATA_VERSION |
Numer wersji tego wiersza. | Dostawca kontaktów automatycznie zwiększa tę wartość za każdym razem, gdy wiersz danych została zmieniona. |
ContactsContract.RawContacts |
SOURCE_ID |
Wartość ciągu znaków, która jednoznacznie identyfikuje ten surowy kontakt na koncie, na którym został utworzony. |
Gdy adapter synchronizacji tworzy nowy nieprzetworzony kontakt, w tej kolumnie należy ustawić wartość
unikalny identyfikator serwera dla nieprzetworzonego kontaktu. Gdy aplikacja na Androida tworzy nowy kontakt w postaci surowych danych, powinna pozostawić tę kolumnę pustą. To sygnał do synchronizacji
że powinien on utworzyć na serwerze nowy nieprzetworzony kontakt i uzyskać
w polu SOURCE_ID .
Identyfikator źródła musi być niepowtarzalny w przypadku każdego typu konta i powinien być stabilny podczas synchronizacji:
|
ContactsContract.Groups |
GROUP_VISIBLE |
„0” - Kontakty w tej grupie nie powinny być widoczne w interfejsach aplikacji na Androida. | Ta kolumna zapewnia zgodność z serwerami, które umożliwiają użytkownikowi ukrywanie kontaktów na pewnych grup. |
„1” – kontakty w tej grupie mogą być widoczne w interfejsie aplikacji. | |||
ContactsContract.Settings |
UNGROUPED_VISIBLE |
„0” - W przypadku tego konta i typu konta kontakty, które nie należą do grupy, są niewidoczne dla UI aplikacji na Androida. |
Domyślnie kontakty są niewidoczne, jeśli żaden z ich nieprzetworzonych kontaktów nie należy do grupy
(Członkostwo w grupie w przypadku nieprzetworzonego kontaktu jest określane przez co najmniej jedną
ContactsContract.CommonDataKinds.GroupMembership wierszy
w tabeli ContactsContract.Data ).
Ustawiając tę flagę w wierszu tabeli ContactsContract.Settings
w przypadku konta i rodzaju konta możesz wymusić wyświetlanie kontaktów bez grup.
Ta flaga może służyć między innymi do wyświetlania kontaktów z serwerów, które nie używają grup.
|
„1” – w przypadku tego konta i typu konta kontakty, które nie należą do grupy, są widoczne w interfejsie aplikacji. | |||
ContactsContract.SyncState |
(wszystkie) | Używaj tej tabeli do przechowywania metadanych adaptera synchronizacji. | Dzięki tej tabeli możesz przechowywać stan synchronizacji i inne dane związane z synchronizacją na urządzeniu. |
Dostęp dostawcy kontaktów
W tej sekcji znajdziesz wytyczne dotyczące uzyskiwania dostępu do danych od dostawcy danych kontaktowych. Omówiono w niej te kwestie:
- Zapytania dotyczące encji.
- Modyfikacja zbiorcza.
- wyszukiwanie i modyfikowanie za pomocą intencji;
- Integralność danych.
Więcej informacji o modyfikowaniu za pomocą adaptera synchronizacji znajdziesz w sekcji Adaptery synchronizacji dostawcy kontaktów.
Wysyłanie zapytań dotyczących encji
Tabele dostawcy kontaktów są uporządkowane hierarchicznie, dlatego często warto pobrać wiersz i wszystkie połączone z nim wiersze „podrzędne”. Aby na przykład wyświetlić wszystkie informacje o konkretnej osobie, możesz pobrać wszystkie wiersze ContactsContract.RawContacts
w przypadku pojedynczego wiersza ContactsContract.Contacts
lub wszystkie wiersze ContactsContract.CommonDataKinds.Email
w przypadku pojedynczego wiersza ContactsContract.RawContacts
. Aby ułatwić to zadanie, usługa ContactsProvider udostępnia konstrukcje elementu, które działają jak złączenia baz danych między tabelami.
Entia jest jak tabela utworzona z wybranych kolumn z tabeli nadrzędnej i jej tabeli podrzędnej.
Przy wysyłaniu zapytania dotyczącego encji podajesz prognozowanie i kryteria wyszukiwania na podstawie kolumn
dostępnych od podmiotu. W wyniku otrzymujesz tablicę Cursor
, która zawiera po 1 wierszu na każdy pobrany wiersz tabeli podrzędnej. Na przykład, jeśli zapytanie
ContactsContract.Contacts.Entity
na imię i nazwisko kontaktu
oraz wszystkie wiersze ContactsContract.CommonDataKinds.Email
dla wszystkich
nieprzetworzone kontakty dla tej nazwy otrzymasz zwrot Cursor
zawierający 1 wiersz
dla każdego wiersza ContactsContract.CommonDataKinds.Email
.
Elementy upraszczają zapytania. Za pomocą tego elementu możesz od razu pobrać wszystkie dane kontaktów dotyczące kontaktu lub surowego kontaktu zamiast najpierw wysyłać zapytanie do tabeli nadrzędnej, aby uzyskać identyfikator, a potem wysyłać zapytanie do tabeli podrzędnej z tym identyfikatorem. Dostawca kontaktów przetwarza też zapytanie dotyczące danego podmiotu w ramach jednej transakcji, co zapewnia spójność wewnętrzną pobieranych danych.
Uwaga: encja zwykle nie zawiera wszystkich kolumn tabeli nadrzędnej i podrzędnej. Jeśli próbujesz użyć nazwy kolumny, której nie ma na liście nazw kolumn
stałe dla encji, otrzymasz Exception
.
Ten fragment kodu pokazuje, jak pobrać wszystkie wiersze kontaktu w postaci nieprzetworzonej. Fragment kodu
jest częścią większej aplikacji, która zawiera 2 czynności: „główna” i „szczegóły”. główną aktywność,
wyświetla listę wierszy kontaktów; gdy użytkownik wybierze jedną z nich, aktywność wysyła do szczegółów swój identyfikator.
działania. Aktywność szczegółów korzysta z pola ContactsContract.Contacts.Entity
aby wyświetlić wszystkie wiersze danych ze wszystkich nieprzetworzonych kontaktów powiązanych z wybranymi
kontakt.
Ten fragment pochodzi ze „szczegółów” aktywność:
Kotlin
... /* * Appends the entity path to the URI. In the case of the Contacts Provider, the * expected URI is content://com.google.contacts/#/entity (# is the ID value). */ contactUri = Uri.withAppendedPath( contactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY ) // Initializes the loader identified by LOADER_ID. loaderManager.initLoader( LOADER_ID, // The identifier of the loader to initialize null, // Arguments for the loader (in this case, none) this // The context of the activity ) // Creates a new cursor adapter to attach to the list view cursorAdapter = SimpleCursorAdapter( this, // the context of the activity R.layout.detail_list_item, // the view item containing the detail widgets mCursor, // the backing cursor fromColumns, // the columns in the cursor that provide the data toViews, // the views in the view item that display the data 0) // flags // Sets the ListView's backing adapter. rawContactList.adapter = cursorAdapter ... override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { /* * Sets the columns to retrieve. * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. * DATA1 contains the first column in the data row (usually the most important one). * MIMETYPE indicates the type of data in the data row. */ val projection: Array<String> = arrayOf( ContactsContract.Contacts.Entity.RAW_CONTACT_ID, ContactsContract.Contacts.Entity.DATA1, ContactsContract.Contacts.Entity.MIMETYPE ) /* * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw * contact collated together. */ val sortOrder = "${ContactsContract.Contacts.Entity.RAW_CONTACT_ID} ASC" /* * Returns a new CursorLoader. The arguments are similar to * ContentResolver.query(), except for the Context argument, which supplies the location of * the ContentResolver to use. */ return CursorLoader( applicationContext, // The activity's context contactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder // Sort by the raw contact ID. ) }
Java
... /* * Appends the entity path to the URI. In the case of the Contacts Provider, the * expected URI is content://com.google.contacts/#/entity (# is the ID value). */ contactUri = Uri.withAppendedPath( contactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY); // Initializes the loader identified by LOADER_ID. getLoaderManager().initLoader( LOADER_ID, // The identifier of the loader to initialize null, // Arguments for the loader (in this case, none) this); // The context of the activity // Creates a new cursor adapter to attach to the list view cursorAdapter = new SimpleCursorAdapter( this, // the context of the activity R.layout.detail_list_item, // the view item containing the detail widgets mCursor, // the backing cursor fromColumns, // the columns in the cursor that provide the data toViews, // the views in the view item that display the data 0); // flags // Sets the ListView's backing adapter. rawContactList.setAdapter(cursorAdapter); ... @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { /* * Sets the columns to retrieve. * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. * DATA1 contains the first column in the data row (usually the most important one). * MIMETYPE indicates the type of data in the data row. */ String[] projection = { ContactsContract.Contacts.Entity.RAW_CONTACT_ID, ContactsContract.Contacts.Entity.DATA1, ContactsContract.Contacts.Entity.MIMETYPE }; /* * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw * contact collated together. */ String sortOrder = ContactsContract.Contacts.Entity.RAW_CONTACT_ID + " ASC"; /* * Returns a new CursorLoader. The arguments are similar to * ContentResolver.query(), except for the Context argument, which supplies the location of * the ContentResolver to use. */ return new CursorLoader( getApplicationContext(), // The activity's context contactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder); // Sort by the raw contact ID. }
Po zakończeniu wczytywania LoaderManager
wywołuje funkcję wywołania zwrotnego onLoadFinished()
. Jednym z argumentów tej metody jest obiekt Cursor
z wynikami zapytania. W swojej aplikacji możesz pobierać dane z tego pliku Cursor
, aby wyświetlać je lub dalej z nimi pracować.
Modyfikacja zbiorcza
Gdy tylko jest to możliwe, należy wstawiać, aktualizować i usuwać dane dostawcy kontaktów w
w trybie zbiorczym, tworząc ArrayList
ContentProviderOperation
obiektów i wywołanie
applyBatch()
Ponieważ dostawca kontaktów wykonuje wszystkie operacje w applyBatch()
w ramach jednej transakcji, wprowadzone przez Ciebie zmiany nigdy nie opuszczą repozytorium kontaktów w stanie niezgodnym z innymi. Modyfikowanie wsadowe ułatwia też wstawienie nieprzetworzonego kontaktu i jego szczegółowych danych w
o tej samej nazwie.
Uwaga: aby zmodyfikować pojedynczy nieprzetworzony kontakt, rozważ wysłanie intencji do aplikacji do obsługi kontaktów na urządzeniu, a nie modyfikować modyfikację w aplikacji. Szczegółowy opis tej czynności znajdziesz w sekcji Pobieranie i modyfikowanie z myślą o pobieraniu danych.
Punkty zysku
Modyfikacja zbiorcza zawierająca dużą liczbę operacji może blokować inne procesy, co może powodować ogólnie nieprzyjemne wrażenia użytkowników. Aby uporządkować wszystkie modyfikacje, które chcesz wprowadzić
w jak najmniejszej liczbie oddzielnych list i jednocześnie uniemożliwiać im
blokując system, ustaw punkty zysku dla co najmniej jednej operacji.
Punkt zysku to obiekt ContentProviderOperation
, który ma określony
Wartość isYieldAllowed()
została ustawiona na
true
Gdy Dostawca kontaktów napotka punkt zysku, wstrzymuje pracę, aby
pozwól innym procesom na uruchomienie i zamyka bieżącą transakcję. Gdy dostawca uruchomi się od nowa,
będzie kontynuowana przy następnej operacji w ArrayList
i rozpocznie nową
transakcji.
Punkty zysku skutkują więcej niż jedną transakcją na wywołanie
applyBatch()
Z powodu
ustaw punkt zysku dla ostatniej operacji dla zbioru powiązanych wierszy.
Punkt zysku należy na przykład ustawić dla ostatniej operacji w zestawie, który dodaje
nieprzetworzone wiersze kontaktów i powiązane z nimi wiersze danych lub ostatnia operacja na zbiorze powiązanych wierszy
z konkretnym kontaktem.
Punkty zysku to również niepodzielne operacje. Każdy dostęp między 2 punktami zysku w ramach jednej jednostki. Jeśli nie ustawisz żadnych punktów zwrotu, najmniejszą operacją atomową będzie cały zestaw operacji. Stosując punkty zysku, przed obniżeniem wydajności systemu, jednocześnie zapewniając, że podzbiór ma bardzo wąski charakter.
Wcześniejsze odwołania po wprowadzeniu zmian
Gdy wstawiasz nowy wiersz nieprzetworzonego kontaktu i powiązane z nim wiersze danych jako zbiór
ContentProviderOperation
obiektów, musisz połączyć wiersze danych
wiersz nieprzetworzonego kontaktu przez wstawienie jego nieprzetworzonego kontaktu
_ID
jako
Wartość RAW_CONTACT_ID
. Ta wartość nie jest jednak dostępna, gdy tworzysz kolumnę danych ContentProviderOperation
, ponieważ nie została jeszcze zastosowana w kolumnie z nieprzetworzonymi danymi o kontaktach. Aby obejść ten problem,
klasa ContentProviderOperation.Builder
ma metodę
withValueBackReference()
Ta metoda umożliwia wstawianie lub modyfikowanie kolumny za pomocą wyniku poprzedniej operacji.
Metoda withValueBackReference()
ma 2 argumenty:
-
key
- Klucz w parze klucz-wartość. Wartość tego argumentu powinna być nazwą kolumny w modyfikowanej tabeli.
-
previousResult
-
Indeks zaczynający się od 0 dla wartości w tablicy
ContentProviderResult
obiektów zapplyBatch()
Jako jeśli stosowane są operacje wsadowe, wyniki każdej z nich są przechowywane w pliku pośrednia tablica wyników. WartośćpreviousResult
jest indeksem. jednego z tych wyników, który jest pobierany i przechowywany przez funkcjękey
. Umożliwia to wstawienie nowego rekordu kontaktu i przywrócenie jego_ID
, a następnie utwórz „odwołanie wsteczne”. do gdy dodasz wierszContactsContract.Data
.Cały tablicowy zbiór wyników jest tworzony podczas pierwszego wywołania funkcji
applyBatch()
, a jego rozmiar jest równy rozmiarowi tablicyArrayList
obiektówContentProviderOperation
. Jednak wszystkie elementy tablicy wyników są ustawione nanull
, a jeśli spróbujesz aby utworzyć odwołanie wstecz do wyniku operacji, która nie została jeszcze zastosowana,withValueBackReference()
trafiaException
.
Z poniższych fragmentów kodu dowiesz się, jak wstawić zbiorczo nowe nieprzetworzone kontakty i dane. Zawierają one kod, który określa punkt zwrotu i używa odwołania wstecznego.
Pierwszy fragment kodu pobiera dane kontaktów z interfejsu. W tym momencie użytkownik wybrał już konto, na którym ma zostać dodany nowy kontakt w postaci danych.
Kotlin
// Creates a contact entry from the current UI values, using the currently-selected account. private fun createContactEntry() { /* * Gets values from the UI */ val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val phoneType: String = contactPhoneTypes[mContactPhoneTypeSpinner.selectedItemPosition] val emailType: String = contactEmailTypes[mContactEmailTypeSpinner.selectedItemPosition]
Java
// Creates a contact entry from the current UI values, using the currently-selected account. protected void createContactEntry() { /* * Gets values from the UI */ String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); int phoneType = contactPhoneTypes.get( contactPhoneTypeSpinner.getSelectedItemPosition()); int emailType = contactEmailTypes.get( contactEmailTypeSpinner.getSelectedItemPosition());
Ten fragment kodu tworzy operację wstawiania wiersza kontaktu w postaci surowych danych do tabeli ContactsContract.RawContacts
:
Kotlin
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. val ops = arrayListOf<ContentProviderOperation>() /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ var op: ContentProviderOperation.Builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.name) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.type) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
/* * Prepares the batch operation for inserting a new raw contact and its data. Even if * the Contacts Provider does not have any data for this person, you can't add a Contact, * only a raw contact. The Contacts Provider will then add a Contact automatically. */ // Creates a new array of ContentProviderOperation objects. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); /* * Creates a new raw contact with its account type (server type) and account name * (user's account). Remember that the display name is not stored in this row, but in a * StructuredName data row. No other data is required. */ ContentProviderOperation.Builder op = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Builds the operation and adds it to the array of operations ops.add(op.build());
Następnie kod tworzy wiersze danych dla wyświetlanej nazwy, numeru telefonu i adresu e-mail.
Każdy obiekt kreatora operacji używa funkcji
withValueBackReference()
do uzyskiwania wartości
RAW_CONTACT_ID
. Punkty odniesienia
z powrotem do obiektu ContentProviderResult
z pierwszej operacji,
który dodaje wiersz nieprzetworzonego kontaktu i zwraca nowy wiersz _ID
.
. W efekcie każdy wiersz danych jest automatycznie powiązany za pomocą kolumny
RAW_CONTACT_ID
z nowym wierszem ContactsContract.RawContacts
, do którego należy.
Obiekt ContentProviderOperation.Builder
, który dodaje wiersz adresu e-mail, to
oznaczony parametrem withYieldAllowed()
, który ustawia punkt zysku:
Kotlin
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType) // Builds the operation and adds it to the array of operations ops.add(op.build()) // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType) /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true) // Builds the operation and adds it to the array of operations ops.add(op.build())
Java
// Creates the display name for the new raw contact, as a StructuredName data row. op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * withValueBackReference sets the value of the first argument to the value of * the ContentProviderResult indexed by the second argument. In this particular * call, the raw contact ID column of the StructuredName data row is set to the * value of the result returned by the first operation, which is the one that * actually adds the raw contact row. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to StructuredName .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) // Sets the data row's display name to the name in the UI. .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified phone number and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Sets the phone number and type .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); // Builds the operation and adds it to the array of operations ops.add(op.build()); // Inserts the specified email and type as a Phone data row op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) /* * Sets the value of the raw contact id column to the new raw contact ID returned * by the first operation in the batch. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Sets the email address and type .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); /* * Demonstrates a yield point. At the end of this insert, the batch operation's thread * will yield priority to other threads. Use after every set of operations that affect a * single contact, to avoid degrading performance. */ op.withYieldAllowed(true); // Builds the operation and adds it to the array of operations ops.add(op.build());
Ostatni fragment zawiera wywołanie
applyBatch()
, które
wstawia nowy nieprzetworzony kontakt i wiersze danych.
Kotlin
// Ask the Contacts Provider to create a new contact Log.d(TAG, "Selected account: ${mSelectedAccount.name} (${mSelectedAccount.type})") Log.d(TAG, "Creating contact: $name") /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) } catch (e: Exception) { // Display a warning val txt: String = getString(R.string.contactCreationFailure) Toast.makeText(applicationContext, txt, Toast.LENGTH_SHORT).show() // Log exception Log.e(TAG, "Exception encountered while inserting contact: $e") } }
Java
// Ask the Contacts Provider to create a new contact Log.d(TAG,"Selected account: " + selectedAccount.getName() + " (" + selectedAccount.getType() + ")"); Log.d(TAG,"Creating contact: " + name); /* * Applies the array of ContentProviderOperation objects in batch. The results are * discarded. */ try { getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); } catch (Exception e) { // Display a warning Context ctx = getApplicationContext(); CharSequence txt = getString(R.string.contactCreationFailure); int duration = Toast.LENGTH_SHORT; Toast toast = Toast.makeText(ctx, txt, duration); toast.show(); // Log exception Log.e(TAG, "Exception encountered while inserting contact: " + e); } }
Operacje zbiorcze umożliwiają też stosowanie optymizmu kontroli współbieżności, czyli metody stosowania transakcji modyfikacji bez konieczności blokowania repozytorium źródłowego. Aby użyć tej metody, zastosuj transakcję, a potem sprawdź, czy w tym samym czasie nie zostały wprowadzone inne modyfikacje. Jeśli zauważysz niespójną modyfikację, wycofaj transakcję i spróbuj ponownie.
Optymalna kontrola równoczesności przydaje się na urządzeniach mobilnych, na których w domenie jest tylko jeden użytkownik i jednoczesny dostęp do repozytorium danych jest rzadki. Ponieważ blokowanie nie jest używane, nie traci się czasu na ustawianie blokad ani na oczekiwanie na ich odblokowanie przez inne transakcje.
Aby używać optymistycznej kontroli równoczesności podczas aktualizowania pojedynczej
ContactsContract.RawContacts
wiersz, wykonaj te czynności:
-
Pobierz
VERSION
nieprzetworzonego kontaktu wraz z innymi pobranymi danymi. -
Utwórz obiekt
ContentProviderOperation.Builder
odpowiedni dla wymuszania ograniczenia za pomocą metodynewAssertQuery(Uri)
W przypadku identyfikatora URI treści użyj funkcjiRawContacts.CONTENT_URI
z dołączonym ciągiem_ID
nieprzetworzonego kontaktu. -
W przypadku obiektu
ContentProviderOperation.Builder
wywołajwithValue()
, aby porównaćVERSION
do pobranej wersji. -
W przypadku tej samej wartości (
ContentProviderOperation.Builder
) zadzwoń:withExpectedCount()
, aby mieć pewność, że to asercja testuje tylko 1 wiersz. -
Wywołaj funkcję
build()
, aby utworzyć obiektContentProviderOperation
, a potem dodaj go jako pierwszy obiekt w obiekcieArrayList
, który przekazujesz do funkcjiapplyBatch()
. - Zastosuj transakcję zbiorczą.
Jeśli wiersz nieprzetworzonego kontaktu został zaktualizowany przez inną operację między odczytaniem wiersza a
przy próbie jego zmodyfikowania komponent ContentProviderOperation
zakończy się niepowodzeniem i zostanie wycofana cała grupa operacji. Możesz wtedy ponownie przesłać tę partię lub wykonać inne działanie.
Poniższy fragment kodu pokazuje, jak utworzyć „assert”ContentProviderOperation
po wysłaniu zapytania o pojedynczy nieprzetworzony kontakt za pomocą CursorLoader
:
Kotlin
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)) mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)) } ... // Sets up a Uri for the assert operation val rawContactUri: Uri = ContentUris.withAppendedId( ContactsContract.RawContacts.CONTENT_URI, rawContactID ) // Creates a builder for the assert operation val assertOp: ContentProviderOperation.Builder = ContentProviderOperation.newAssertQuery(rawContactUri).apply { // Adds the assertions to the assert operation: checks the version withValue(SyncColumns.VERSION, mVersion) // and count of rows tested withExpectedCount(1) } // Creates an ArrayList to hold the ContentProviderOperation objects val ops = arrayListOf<ContentProviderOperation>() ops.add(assertOp.build()) // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { val results: Array<ContentProviderResult> = contentResolver.applyBatch(AUTHORITY, ops) } catch (e: OperationApplicationException) { // Actions you want to take if the assert operation fails go here }
Java
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Gets the raw contact's _ID and VERSION values rawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); } ... // Sets up a Uri for the assert operation Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactID); // Creates a builder for the assert operation ContentProviderOperation.Builder assertOp = ContentProviderOperation.newAssertQuery(rawContactUri); // Adds the assertions to the assert operation: checks the version and count of rows tested assertOp.withValue(SyncColumns.VERSION, mVersion); assertOp.withExpectedCount(1); // Creates an ArrayList to hold the ContentProviderOperation objects ArrayList ops = new ArrayList<ContentProviderOperation>; ops.add(assertOp.build()); // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { ContentProviderResult[] results = getContentResolver().applyBatch(AUTHORITY, ops); } catch (OperationApplicationException e) { // Actions you want to take if the assert operation fails go here }
Pobieranie i modyfikowanie za pomocą intencji
Wysyłanie intencji do aplikacji kontaktów na urządzeniu umożliwia pośredni dostęp do dostawcy kontaktów. Intencje uruchamiają interfejs aplikacji Kontakty na urządzeniu, w której użytkownicy mogą wykonywać czynności związane z kontaktami. Dzięki temu rodzajowi dostępu użytkownicy mogą:
- Wybierz kontakt z listy i zwróć go do aplikacji, aby kontynuować pracę.
- Edytowanie danych istniejącego kontaktu.
- Wstaw nowy kontakt w postaci tekstu zwykłego na dowolnym koncie.
- usunąć dane kontaktu lub kontaktów;
Jeśli użytkownik wstawia lub aktualizuje dane, możesz najpierw zebrać te dane i wysłać je jako część intencji.
Gdy używasz intencji do uzyskania dostępu do dostawcy kontaktów za pomocą aplikacji do obsługi kontaktów na urządzeniu, nie muszą pisać własnego interfejsu użytkownika ani kodu umożliwiającego dostęp do dostawcy. Nie musisz też prosić o dostęp do odczytu ani zapisu w przypadku dostawcy. Aplikacja kontaktów na urządzeniu może przyznać Ci uprawnienia do odczytu kontaktu, a ponieważ wprowadzasz zmiany w przez inną aplikację, nie musisz mieć uprawnień do zapisu.
Ogólny proces wysyłania intencji dostępu do dostawcy został szczegółowo opisany w
Przewodnik po podstawach dostawców treści w sekcji „Dostęp do danych za pomocą intencji”. Akcja,
Typ MIME i wartości danych używane w dostępnych zadaniach zostały podsumowane w tabeli 4,
wartości dodatkowe, których można używać
putExtra()
znajdują się w
dokumentacja dla ContactsContract.Intents.Insert
:
Tabela 4. Intencje dostawcy kontaktów.
Zadanie | Działanie | Dane | Typ MIME | Uwagi |
---|---|---|---|---|
Wybieranie kontaktu z listy | ACTION_PICK |
Jedna z tych możliwości:
|
Bez lampy |
Wyświetla listę nieprzetworzonych kontaktów lub listę danych z nieprzetworzonego kontaktu, w zależności od podawanego typu identyfikatora URI treści.
Zadzwoń do nas
|
Wstawianie nowego niesformatowanego kontaktu | Insert.ACTION |
Nie dotyczy |
RawContacts.CONTENT_TYPE , typ MIME dla zbioru nieprzetworzonych kontaktów.
|
Wyświetla ekran Dodaj kontakt w aplikacji Kontakty na urządzeniu. Wyświetlają się wartości dodatkowych informacji dodane do intencji. Jeśli wysłano z
startActivityForResult() ,
identyfikator URI treści nowo dodanego nieprzetworzonego kontaktu jest przekazywany z powrotem do modułu
onActivityResult()
metody wywołania zwrotnego w argumencie Intent w funkcji
„dane” . Aby uzyskać wartość, wywołaj funkcję getData() .
|
Edytowanie kontaktu | ACTION_EDIT |
CONTENT_LOOKUP_URI dla
kontakt. Aktywność edytora pozwoli użytkownikowi edytować dowolne dane powiązane z tym kontaktem.
|
Contacts.CONTENT_ITEM_TYPE , jeden kontakt. |
Wyświetla ekran Edytuj kontakt w aplikacji kontaktów. dodane przez Ciebie wartości dodatkowe; do intencji. Gdy użytkownik kliknie Gotowe, aby zapisać zmiany, Twoja aktywność powróci na pierwszy plan. |
Wyświetl selektor, który może też dodawać dane. | ACTION_INSERT_OR_EDIT |
Nie dotyczy |
CONTENT_ITEM_TYPE
|
Ta intencja zawsze wyświetla ekran wyboru aplikacji kontaktów. Użytkownik może wykonać jedną z tych czynności:
wybierz kontakt, który chcesz edytować, lub dodaj nowy. Ekran edycji lub dodawania
w zależności od wyboru użytkownika oraz danych dodatkowych przekazywanych w zamiarze
Jeśli aplikacja wyświetla dane kontaktów, takie jak adres e-mail lub numer telefonu, użyj funkcji
Dzięki temu użytkownik będzie mógł dodać dane do istniejącego kontaktu.
kontakt,
Uwaga: w dodatkach tej intencji nie trzeba wysyłać wartości nazwy. bo użytkownik zawsze wybiera istniejącą nazwę lub dodaje nową. Ponadto, gdy wyślesz nazwę, a użytkownik zdecyduje się ją edytować, aplikacja do obsługi kontaktów wyświetlić nadesłaną nazwę, zastępując poprzednią wartość. Jeśli użytkownik nie wyrazi zgody, zauważy to i zapisze zmianę, stara wartość zostaje utracona. |
Aplikacja Kontakty na urządzeniu nie pozwala na usunięcie nieprzetworzonego kontaktu ani żadnych jego danych za pomocą intencji. Aby usunąć nieprzetworzony kontakt, należy użyć funkcji
ContentResolver.delete()
lub ContentProviderOperation.newDelete()
.
Ten fragment kodu pokazuje, jak utworzyć i wysłać intencję, która wstawi nowy nieprzetworzony kontakty i dane:
Kotlin
// Gets values from the UI val name = contactNameEditText.text.toString() val phone = contactPhoneEditText.text.toString() val email = contactEmailEditText.text.toString() val company = companyName.text.toString() val jobtitle = jobTitle.text.toString() /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row val contactData = arrayListOf<ContentValues>() /* * Defines the raw contact row */ // Sets up the row as a ContentValues object val rawContactRow = ContentValues().apply { // Adds the account type and name to the row put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.type) put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.name) } // Adds the row to the array contactData.add(rawContactRow) /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object val phoneRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) // Adds the phone number and its type to the row put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) } // Adds the row to the array contactData.add(phoneRow) /* * Sets up the email data row */ // Sets up the row as a ContentValues object val emailRow = ContentValues().apply { // Specifies the MIME type for this data row (all data rows must be marked by their type) put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) // Adds the email address and its type to the row put(ContactsContract.CommonDataKinds.Email.ADDRESS, email) } // Adds the row to the array contactData.add(emailRow) // Creates a new intent for sending to the device's contacts application val insertIntent = Intent(ContactsContract.Intents.Insert.ACTION).apply { // Sets the MIME type to the one expected by the insertion activity type = ContactsContract.RawContacts.CONTENT_TYPE // Sets the new contact name putExtra(ContactsContract.Intents.Insert.NAME, name) // Sets the new company and job title putExtra(ContactsContract.Intents.Insert.COMPANY, company) putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle) /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData) } // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent)
Java
// Gets values from the UI String name = contactNameEditText.getText().toString(); String phone = contactPhoneEditText.getText().toString(); String email = contactEmailEditText.getText().toString(); String company = companyName.getText().toString(); String jobtitle = jobTitle.getText().toString(); // Creates a new intent for sending to the device's contacts application Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION); // Sets the MIME type to the one expected by the insertion activity insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE); // Sets the new contact name insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name); // Sets the new company and job title insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle); /* * Demonstrates adding data rows as an array list associated with the DATA key */ // Defines an array list to contain the ContentValues objects for each row ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); /* * Defines the raw contact row */ // Sets up the row as a ContentValues object ContentValues rawContactRow = new ContentValues(); // Adds the account type and name to the row rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, selectedAccount.getType()); rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, selectedAccount.getName()); // Adds the row to the array contactData.add(rawContactRow); /* * Sets up the phone number data row */ // Sets up the row as a ContentValues object ContentValues phoneRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) phoneRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ); // Adds the phone number and its type to the row phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone); // Adds the row to the array contactData.add(phoneRow); /* * Sets up the email data row */ // Sets up the row as a ContentValues object ContentValues emailRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) emailRow.put( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ); // Adds the email address and its type to the row emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email); // Adds the row to the array contactData.add(emailRow); /* * Adds the array to the intent's extras. It must be a parcelable object in order to * travel between processes. The device's contacts app expects its key to be * Intents.Insert.DATA */ insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); // Send out the intent to start the device's contacts app in its add contact activity. startActivity(insertIntent);
Integralność danych
Repozytorium kontaktów zawiera ważne i wrażliwe dane, które użytkownicy oczekują, że będą poprawne i aktualne. Dlatego dostawca kontaktów ma dobrze zdefiniowane zasady dotyczące integralności danych. Jest ponosisz odpowiedzialność za przestrzeganie tych zasad podczas modyfikowania danych kontaktowych. Ważne reguły są wymienione tutaj:
-
Dodaj wiersz
ContactsContract.CommonDataKinds.StructuredName
do każdego dodanego wierszaContactsContract.RawContacts
. - Wiersz
ContactsContract.RawContacts
bez wierszaContactsContract.CommonDataKinds.StructuredName
w tabeliContactsContract.Data
może powodować problemy podczas agregacji. -
Nowe wiersze
ContactsContract.Data
zawsze łącz z wierszem nadrzędnymContactsContract.RawContacts
. -
Wiersz
ContactsContract.Data
, który nie jest połączony z tabeląContactsContract.RawContacts
nie będzie widoczny w: aplikacji do kontaktów, co może powodować problemy z adapterami synchronizacji. - Zmieniaj dane tylko w przypadku tych nieprzetworzonych kontaktów, które należą do Ciebie.
- Pamiętaj, że dostawca kontaktów zwykle zarządza danymi z kilku różnych typów kont i usług online. Musisz się upewnić, że aplikacja modyfikuje lub usuwa tylko dane w wierszach, które należą do Ciebie, oraz że wstawia dane tylko z typem i nazwą konta, które są pod Twoją kontrolą.
-
Zawsze używaj stałych określonych w zasadzie
ContactsContract
i jej podklasy urzędów, identyfikatorów URI treści, ścieżek URI, nazw kolumn, typów MIME orazTYPE
wartości. - Użycie tych stałych pozwala uniknąć błędów. Otrzymasz też powiadomienie z kompilatorem , jeśli któraś ze stałych jest nieużywana.
Niestandardowe wiersze danych
Po utworzeniu i użyciu własnych typów MIME możesz w tabeli ContactsContract.Data
wstawiać, edytować, usuwać i pobierać własne wiersze danych. Twoje wiersze
są ograniczone do używania kolumny zdefiniowanej w
ContactsContract.DataColumns
, ale możesz tworzyć własne mapy
specyficzne dla danego typu nazw kolumn na domyślne. W aplikacji Kontakty na urządzeniu wyświetlane są dane Twoich wierszy, ale nie można ich edytować ani usuwać, a użytkownicy nie mogą dodawać dodatkowych danych. Aby umożliwić użytkownikom modyfikowanie wierszy danych niestandardowych, musisz udostępnić w swojej aplikacji aktywność edytora.
Aby wyświetlić dane niestandardowe, prześlij plik contacts.xml
zawierający
<ContactsAccountType>
i co najmniej jeden jego element
Elementy podrzędne: <ContactsDataKind>
. Więcej informacji znajdziesz w sekcji <ContactsDataKind> element
.
Więcej informacji o niestandardowych typach MIME znajdziesz w Przewodnik po tworzeniu treści dla dostawcy treści.
Adaptery synchronizacji dostawcy kontaktów
Dostawca kontaktów został zaprojektowany specjalnie do obsługi synchronizacji danych kontaktów między urządzeniem a usługą online. Dzięki temu użytkownicy mogą pobierać istniejące dane na nowe urządzenie oraz przesyłać istniejące dane na nowe konto. Synchronizacja zapewnia też, że użytkownicy mają najnowsze dane, niezależnie od źródła dodatków i zmian. Kolejną zaletą synchronizacji jest to, że dane kontaktów są dostępne nawet wtedy, gdy urządzenie nie jest połączone z siecią.
Chociaż synchronizację można wdrożyć na wiele sposobów, system Android zapewnia platformę synchronizacji wtyczek, która automatyzuje następujące zadania:
- Sprawdzam dostępność sieci.
- planowanie i przeprowadzanie synchronizacji na podstawie preferencji użytkownika;
- Ponownie uruchamiam zatrzymane synchronizacje.
Aby korzystać z tej platformy, musisz dostarczyć wtyczkę synchronizatora. Każdy adapter synchronizacji ma swój dostawcy usług i treści, ale może obsługiwać wiele nazw kont w ramach tej samej usługi. Framework umożliwia też stosowanie wielu adapterów synchronizacji w przypadku tej samej usługi i dostawcy.
Klasy i pliki adaptera synchronizacji
Implementujesz adapter synchronizacji jako podklasęAbstractThreadedSyncAdapter
i instalujesz go w ramach aplikacji na Androida. System uczy się o adapterze synchronizacji na podstawie elementów w aplikacji
ze specjalnego pliku XML wskazanego przez plik manifestu. Plik XML określa
typu konta w usłudze online i urzędu dostawcy treści, które wspólnie
jednoznacznie identyfikować adapter. Adapter synchronizacji nie stanie się aktywny, dopóki użytkownik nie doda konta dla typu konta adaptera synchronizacji i nie włączy synchronizacji dla dostawcy treści, z którym synchronizuje adapter synchronizacji. Wtedy system zaczyna zarządzać adapterem,
w razie potrzeby w celu przeprowadzenia synchronizacji między dostawcą treści a serwerem.
Uwaga: użycie typu konta do identyfikacji adaptera synchronizacji umożliwia
systemu do wykrywania i grupowania adapterów synchronizacji, które uzyskują dostęp do różnych usług
w tej samej organizacji. Na przykład wszystkie adaptery synchronizacji usług online Google mają takie same
typ konta: com.google
. Gdy użytkownicy dodają konto Google na swoich urządzeniach, wszystkie zainstalowane adaptery synchronizacji dla usług Google są wyświetlane razem. Każdy adapter synchronizacji synchronizuje się z innym dostawcą treści na urządzeniu.
Ponieważ większość usług wymaga od użytkowników potwierdzenia tożsamości przed uzyskaniem dostępu
danych system Android oferuje platformę uwierzytelniania podobną do
używane w połączeniu z platformą adaptera synchronizacji. Platforma uwierzytelniania wykorzystuje
wtyczki uwierzytelniające, które należą do podklasy
AbstractAccountAuthenticator
Authenticator weryfikuje tożsamość użytkownika w następujący sposób:
- zbiera nazwę użytkownika, hasło lub podobne informacje ( dane logowania).
- Wysyła dane logowania do usługi.
- Sprawdzanie odpowiedzi usługi.
Jeśli usługa zaakceptuje dane logowania, moduł uwierzytelniający może
zapisać dane logowania do późniejszego użycia. Dzięki frameworkowi wtyczki uwierzytelniającej AccountManager
może ona udostępniać dostęp do dowolnych tokenów autoryzacji obsługiwanych przez aplikację uwierzytelniającą i wybieranych przez nią do udostępnienia, takich jak tokeny autoryzacji OAuth 2.
Chociaż uwierzytelnianie nie jest wymagane, większość usług kontaktowych z niego korzysta. Jednak do uwierzytelniania nie musisz używać platformy uwierzytelniania Androida.
Implementacja adaptera synchronizacji
Aby zaimplementować adapter synchronizacji dla dostawcy kontaktów, najpierw utwórz aplikację na Androida, która zawiera:
-
Komponent
Service
, który odpowiada na żądania wysyłane przez system do i połączyć z adapterem synchronizacji. - Gdy system chce uruchomić synchronizację, wywołuje metodę
onBind()
usługi, aby uzyskać obiektIBinder
dla adaptera synchronizacji. Dzięki temu system może między procesami a metodami adaptera. -
Rzeczywisty adapter synchronizacji, zaimplementowany jako konkretny podklasa
AbstractThreadedSyncAdapter
- Ta klasa pobiera dane z serwera, przesyła dane z urządzenia i rozwiązuje konflikty. Główna praca adaptera jest wykonywana w metodie
onPerformSync()
. Ta klasa musi być utworzona jako pojedynczy element. -
Podklasa klasy
Application
. -
Ta klasa działa jako fabryka pojedynczegotonu adaptera synchronizacji. Użyj metody
onCreate()
, aby utworzyć instancję adaptera synchronizacji, i przekaż stałą metodę „gettera”, która zwróci obiekt singleton do metodyonBind()
usługi adaptera synchronizacji. -
Opcjonalnie: komponent
Service
, który odpowiada na żądania systemu dotyczące uwierzytelniania użytkownika. -
AccountManager
uruchamia tę usługę, aby rozpocząć proces uwierzytelniania. MetodaonCreate()
usługi tworzy instancję obiektu authenticator. Gdy system chce uwierzytelnić konto użytkownika dla adapter synchronizacji aplikacji wywołuje metodę MetodaonBind()
, aby uzyskaćIBinder
dla uwierzytelniania. Dzięki temu system może między procesami wywołującymi metody uwierzytelniania. -
Opcjonalnie: konkretny podklas
AbstractAccountAuthenticator
, który obsługuje żądania uwierzytelniania. -
Ta klasa udostępnia metody wywoływane przez funkcję
AccountManager
uwierzytelnienie danych użytkownika na serwerze. Szczegóły proces uwierzytelniania bardzo się różni w zależności od używanej technologii serwera. Zalecenia zapoznaj się z dokumentacją oprogramowania serwera, aby dowiedzieć się więcej o uwierzytelnianiu. - Pliki XML definiujące adapter synchronizacji i mechanizm uwierzytelniający w systemie.
-
Opisane wcześniej komponenty adaptera synchronizacji i usługi uwierzytelniającej to
zdefiniowane w
<service>
elementów pliku manifestu aplikacji. Te elementy zawierają<meta-data>
elementy podrzędne, które dostarczają do systemu określone dane:-
<meta-data>
element usługi adaptera synchronizacji wskazuje Plik XMLres/xml/syncadapter.xml
. Ten plik określa z kolei, identyfikator URI usługi sieciowej, który zostanie zsynchronizowany z dostawcą kontaktów; oraz typ konta usługi sieciowej. -
Opcjonalnie: parametr
<meta-data>
element uwierzytelniający wskazuje na plik XMLres/xml/authenticator.xml
Plik ten określa z kolei typ konta obsługiwany przez ten mechanizm uwierzytelniania, a także zasoby interfejsu użytkownika, które widoczne podczas procesu uwierzytelniania. Typ konta określony w tym elemencie musi być taki sam jak typ konta określony dla adaptera synchronizacji.
-
Dane strumienia społecznościowego
Tabele android.provider.ContactsContract.StreamItems i android.provider.ContactsContract.StreamItemPhotos zarządzają przychodzącymi danymi z sieci społecznościowych. Możesz napisać adapter synchronizacji, który dodaje dane strumienia z Twojej sieci do tych tabel, albo odczytać dane strumienia z tych tabel i wyświetlić je w swojej aplikacji. Możesz też zrobić i jedno, i drugie. Dzięki tym funkcjom usługi i aplikacje do obsługi mediów społecznościowych mogą być zintegrowane z funkcjami mediów społecznościowych w Androidzie.
Tekst strumienia społecznościowego
Elementy strumienia są zawsze powiązane z nieprzetworzonym kontaktem. Parametr android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID łączy się z wartością _ID
w przypadku nieprzetworzonego kontaktu. Rodzaj i nazwa konta nieprzetworzonego
kontakt jest także przechowywany w wierszu elementu strumienia.
Dane ze strumienia możesz zapisać w tych kolumnach:
- android.provider.ContactsContract.StreamItemsKolumny#ACCOUNT_TYPE
- Wymagane. Typ konta użytkownika dla kontaktu surowego powiązanego z tym elementem strumienia. Pamiętaj, aby ustawić tę wartość podczas wstawiania elementu strumienia.
- android.provider.ContactsContract.StreamItemsKolumny#ACCOUNT_NAME
- Wymagane. Nazwa konta użytkownika nieprzetworzonego kontaktu powiązanego z elementu strumieniowego przesyłania danych. Pamiętaj, aby ustawić tę wartość podczas wstawiania elementu strumienia.
- Kolumny identyfikatorów
- Wymagany. Musisz wstawić poniższe kolumny identyfikatorów
wstaw element strumienia:
- android.provider.ContactsContract.StreamItemsKolumny#CONTACT_ID: Atrybut Wartość android.provider.BaseColumn#_ID kontaktu, który wysyła ten strumień Element, z którym jest powiązany element.
- android.provider.ContactsContract.StreamItemsKolumny#CONTACT_LOOKUP_KEY: android.provider.ContactsContract.ContactsColumn#LOOKUP_KEY wartość Skontaktuj się z tym elementem strumienia, z którym jest powiązany ten element strumienia.
- android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID: wartość właściwości android.provider.BaseColumns#_ID nieprzetworzonego kontaktu, z którym jest powiązany ten element strumienia.
- android.provider.ContactsContract.StreamItemsKolumny#COMMENTS
- Opcjonalna. Zapisuje podsumowanie informacji, które możesz wyświetlić na początku elementu strumienia.
- android.provider.ContactsContract.StreamItemsColumns#TEXT
- Tekst elementu strumienia, czyli treści opublikowane przez źródło elementu lub opis działania, które wygenerowało element strumienia. Ta kolumna może zawierać
wszelkie formatowania i osadzone obrazy zasobów, które mogą być renderowane przez
fromHtml()
Dostawca może skrócić lub wielokropek, ale stara treść o unikanie uszkodzenia tagów. - android.provider.ContactsContract.StreamItemsKolumny#TIMESTAMP
- Ciąg tekstowy zawierający czas wstawienia lub zaktualizowania elementu strumienia w formie milisekund od początku epoki. Aplikacje wstawiające lub aktualizujące elementy strumienia są odpowiada za utrzymanie tej kolumny; nie jest automatycznie utrzymywany przez Dostawca kontaktów.
Aby wyświetlić informacje identyfikujące elementy w strumieniu, użyj android.provider.ContactsContract.StreamItemsKolumny#RES_ICON, android.provider.ContactsContract.StreamItemsKolumny#RES_LABEL i android.provider.ContactsContract.StreamItemsColumn#RES_PACKAGE link do zasobów w Twojej aplikacji.
Tabela android.provider.ContactsContract.StreamItems zawiera też kolumny android.provider.ContactsContract.StreamItemsColumns#SYNC1–android.provider.ContactsContract.StreamItemsColumns#SYNC4, które są przeznaczone wyłącznie do użytku przez adaptery synchronizacji.
zdjęcia ze strumienia społecznościowego,
Tabela android.provider.ContactsContract.StreamItemPhotos przechowuje zdjęcia powiązane z elementem strumienia. Tabela
Kolumna android.provider.ContactsContract.StreamItemPhotosColumn#STREAM_ITEM_ID Kolumna
linki do wartości w kolumnie _ID
argumentu
Tabela android.provider.ContactsContract.StreamItems. Odniesienia do zdjęć są przechowywane w tabeli
w tych kolumnach:
- Kolumna android.provider.ContactsContract.StreamItemPhotos#PHOTO (BLOB).
- Binarne przedstawienie zdjęcia, którego rozmiar został zmieniony przez dostawcę w celu przechowywania i wyświetlania. Ta kolumna jest dostępna na potrzeby zgodności wstecznej z poprzednimi wersjami Kontaktów Dostawca, który skorzystał z niego do przechowywania zdjęć. W obecnej wersji nie należy jednak używać tej kolumny do przechowywania zdjęć. Zamiast tego użyj kolumny android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID lub kolumny android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (obie opisane w następnych punktach) do przechowywania zdjęć w pliku. Ta kolumna zawiera teraz miniaturę zdjęcia, którą można odczytać.
- android.provider.ContactsContract.StreamItemPhotosKolumny#PHOTO_FILE_ID
-
Liczbowy identyfikator zdjęcia w przypadku nieprzetworzonego kontaktu. Dodaj tę wartość do stałej
DisplayPhoto.CONTENT_URI
, aby uzyskać identyfikator URI treści wskazujący na pojedynczy plik zdjęcia, a potem wywołaj funkcjęopenAssetFileDescriptor()
, aby uzyskać uchwyt do pliku zdjęcia. - android.provider.ContactsContract.StreamItemPhotosColumn#PHOTO_URI
- Identyfikator URI treści wskazujący bezpośrednio na plik zdjęcia, który reprezentuje ten wiersz.
Wywołaj funkcję
openAssetFileDescriptor()
, podając ten identyfikator URI, aby uzyskać uchwyt dla pliku zdjęcia.
Korzystanie z tabel strumienia społecznościowego
Te tabele działają tak samo jak inne główne tabele dostawcy kontaktów z wyjątkiem tych:
- Te tabele wymagają dodatkowych uprawnień dostępu. Aby odczytać te dane, aplikacja musi mieć uprawnienie android.Manifest.permission#READ_SOCIAL_STREAM. Do ich modyfikowanie, aplikacja musi mieć odpowiednie uprawnienia android.Manifest.permission#WRITE_SOCIAL_STREAM.
-
W tabeli android.provider.ContactsContract.StreamItems jest to liczba wierszy
każdego nieprzetworzonego kontaktu jest ograniczona. Gdy limit zostanie osiągnięty, dostawca kontaktów tworzy miejsce na nowe wiersze elementów strumienia, automatycznie usuwając wiersze z najstarszymi wartościami android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP. Aby uzyskać limit, prześlij zapytanie do identyfikatora URI treści android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI. Możesz opuścić listę
wszystkie argumenty oprócz identyfikatora URI treści ustawione na
null
. Zapytanie zwraca kursor zawierający 1 wiersz, w przypadku którego jedna kolumna android.provider.ContactsContract.StreamItems#MAX_ITEMS.
Klasa android.provider.ContactsContract.StreamItems.StreamItemPhotos definiuje podtabela android.provider.ContactsContract.StreamItemPhotos zawierająca zdjęcie wierszy dla pojedynczego elementu strumienia.
Interakcje w strumieniach społecznościowych
Dane strumienia społecznościowego zarządzane przez dostawcę kontaktów w połączeniu z aplikacją kontaktów na urządzeniu stanowią skuteczny sposób na połączenie systemu sieci społecznościowej z dotychczasowymi kontaktami. Dostępne są te funkcje:
- Dzięki synchronizacji usługi sieci społecznościowej z usługą dostawcy kontaktów za pomocą adaptera synchronizacji możesz pobrać najnowszą aktywność kontaktów użytkownika i przechowywać ją w tablicach android.provider.ContactsContract.StreamItems i android.provider.ContactsContract.StreamItemPhotos na potrzeby późniejszego użycia.
- Oprócz regularnej synchronizacji możesz uruchomić adapter synchronizacji, aby pobrać dodatkowe dane, gdy użytkownik wybierze kontakt do wyświetlenia. Umożliwi to korzystanie z adaptera synchronizacji w celu pobrania zdjęć w wysokiej rozdzielczości oraz najnowszych elementów kontaktu w strumieniu.
- Dzięki zarejestrowaniu powiadomienia w aplikacji Kontakty na urządzeniu i u dostawcy kontaktów możesz otrzymać zamiar, gdy kontakt jest wyświetlany, i w tym momencie zaktualizować stan kontaktu z usługi. Takie podejście może być szybsze i wymagać mniejszej przepustowości niż pełna synchronizacja za pomocą adaptera synchronizacji.
- Użytkownicy mogą dodawać kontakt do Twojej usługi sieci społecznościowej, gdy wyświetlają kontakt w aplikacji kontaktów na urządzeniu. Tę funkcję możesz włączyć za pomocą opcji „zaproś kontakt”. funkcji, które włączysz przez połączenie aktywności dodającej istniejący kontakt do Twojego oraz plik XML z aplikacją do obsługi kontaktów na urządzeniu Dostawca kontaktów z informacjami o Twojej aplikacji.
Regularna synchronizacja elementów strumienia z usługą Kontakty przebiega tak samo jak inne synchronizacje. Więcej informacji na temat synchronizacji znajdziesz w sekcji Adaptery synchronizacji dostawcy kontaktów Rejestrowanie powiadomień oraz dotyczące zapraszania kontaktów zostały omówione w dwóch następnych sekcjach.
Rejestracja w celu obsługi wyświetleń w sieciach społecznościowych
Aby zarejestrować adapter synchronizacji, aby otrzymywać powiadomienia, gdy użytkownik wyświetla kontakt zarządzany przez ten adapter:
-
Utwórz plik o nazwie
contacts.xml
w folderzeres/xml/
projektu katalogu. Jeśli masz już ten plik, możesz pominąć ten krok. -
W tym pliku dodaj element
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
Jeśli ten element już istnieje, możesz pominąć ten krok. -
Aby zarejestrować usługę, która jest powiadamiana, gdy użytkownik otworzy stronę szczegółów kontaktu w aplikacji kontaktów na urządzeniu, dodaj do elementu atrybut
viewContactNotifyService="serviceclass"
, gdzieserviceclass
to w pełni kwalifikowana nazwa klasy usługi, która powinna otrzymać intencję z aplikacji kontaktów na urządzeniu. W przypadku osoby wysyłającej powiadomienie usługi, użyj klasy, która rozszerzaIntentService
, aby umożliwić usłudze przetwarzania intencji. Dane w przychodzącym intencie zawierają identyfikator URI treści kontaktu nieprzetworzonego, na który użytkownik kliknął. W usłudze powiadamiania możesz utworzyć powiązanie z, a następnie wywołać synchronizacji, aby zaktualizować dane nieprzetworzonego kontaktu.
Aby zarejestrować aktywność, która ma być wywoływana, gdy użytkownik kliknie element strumienia lub zdjęcie albo oba te elementy:
-
Utwórz plik o nazwie
contacts.xml
w katalogures/xml/
projektu. Jeśli masz już ten plik, możesz pominąć ten krok. -
W tym pliku dodaj element
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
Jeśli ten element już istnieje, możesz pominąć ten krok. -
Aby zarejestrować jedną z Twoich aktywności jako obsługę użytkownika, który kliknie element w strumieniu
aplikacji do obsługi kontaktów na urządzeniu, dodaj atrybut
viewStreamItemActivity="activityclass"
do elementu, gdzieactivityclass
to w pełni kwalifikowana nazwa klasy aktywności który powinien otrzymywać intencję z aplikacji do kontaktów na urządzeniu. -
Aby zarejestrować jedną z Twoich aktywności jako obsługę użytkownika po kliknięciu zdjęcia w strumieniu
aplikacji do obsługi kontaktów na urządzeniu, dodaj atrybut
viewStreamItemPhotoActivity="activityclass"
do elementu, gdzieactivityclass
to w pełni kwalifikowana nazwa klasy działania. który powinien otrzymywać intencję z aplikacji do kontaktów na urządzeniu.
Element <ContactsAccountType>
jest opisany bardziej szczegółowo w sekcji <ContactsAccountType> element.
Dochodzący zamiar zawiera identyfikator URI treści elementu lub zdjęcia, które użytkownik kliknął. Aby mieć osobne działania dla elementów tekstowych i zdjęć, użyj obu atrybutów w tym samym pliku.
Interakcje z usługami sieci społecznościowych
Użytkownicy nie muszą opuszczać aplikacji Kontakty na urządzeniu, aby zaprosić kontakt do sieci społecznościowej witryny. Możesz jednak skonfigurować aplikację Kontakty na urządzeniu, by wysłała intencję zaproszenia kontakt z jednym z Twoich działań. Aby to skonfigurować:
-
Utwórz plik o nazwie
contacts.xml
w folderzeres/xml/
projektu katalogu. Jeśli masz już taki plik, możesz pominąć ten krok. -
W tym pliku dodaj element
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
Jeśli ten element już istnieje, możesz pominąć ten krok. -
Dodaj te atrybuty:
inviteContactActivity="activityclass"
-
inviteContactActionLabel="@string/invite_action_label"
activityclass
jest pełną i jednoznaczną nazwą klasy klasy działanie, które powinno otrzymać intencję.invite_action_label
jest ciągiem tekstowym wyświetlanym w menu Dodaj połączenie w sekcji aplikacji do obsługi kontaktów na urządzeniu.
Uwaga: ContactsSource
to nazwa tagu, która została zastąpiona tagiem ContactsAccountType
.
Plik contacts.xml
Plik contacts.xml
zawiera elementy XML, które kontrolują interakcje adaptera synchronizacji i aplikacji z aplikacją Kontakty i dostawcą kontaktów. Te elementy są opisane w następnych sekcjach.
<ContactsAccountType> element
Element <ContactsAccountType>
określa interakcję
z aplikacją do obsługi kontaktów. Ma ona taką składnię:
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android" inviteContactActivity="activity_name" inviteContactActionLabel="invite_command_text" viewContactNotifyService="view_notify_service" viewGroupActivity="group_view_activity" viewGroupActionLabel="group_action_text" viewStreamItemActivity="viewstream_activity_name" viewStreamItemPhotoActivity="viewphotostream_activity_name">
Zawiera:
res/xml/contacts.xml
może zawierać:
<ContactsDataKind>
Opis:
Deklaruje komponenty i etykiety interfejsu Androida, które umożliwiają użytkownikom zapraszanie kontaktów do sieci społecznościowej, powiadamianie użytkowników o aktualizacjach strumieni sieci społecznościowych itp.
Zwróć uwagę, że prefiks atrybutu android:
nie jest wymagany dla atrybutów
z <ContactsAccountType>
.
Atrybuty:
inviteContactActivity
- Pełna nazwa klasy aktywności w aplikacji, którą chcesz wykonywać aktywuj, gdy użytkownik wybierze Dodaj połączenie na aplikacji do kontaktów.
inviteContactActionLabel
- Ciąg tekstowy wyświetlany w menu Dodaj połączenie dla aktywności określonej w
inviteContactActivity
. Możesz na przykład użyć ciągu znaków „Obserwuj w mojej sieci”. Możesz użyć zasobu tekstowego, dla tej etykiety. viewContactNotifyService
- Pełna nazwa klasy usługi w aplikacji, która powinna otrzymać powiadomienia, gdy użytkownik wyświetli kontakt. To powiadomienie jest wysyłane przez aplikację Kontakty na urządzeniu. Pozwala aplikacji odłożyć operacje wymagające dużej ilości danych do momentu, gdy będą potrzebne. Na przykład aplikacja może odpowiedzieć na to powiadomienie odczytując i wyświetlając zdjęcie w wysokiej rozdzielczości elementy strumienia społecznościowego. Ta funkcja jest opisana bardziej szczegółowo w sekcji Interakcje w strumieniach społecznościowych.
viewGroupActivity
- Pełna nazwa klasy aktywności w aplikacji, która może wyświetlać informacje o grupie. Gdy użytkownik kliknie etykietę grupy w kontaktach na urządzeniu aplikacji, wyświetli się interfejs dla tej aktywności.
viewGroupActionLabel
-
Etykieta wyświetlana w aplikacji do obsługi kontaktów dla elementu sterującego interfejsu użytkownika, który pozwala
możliwość wglądu w grupy w aplikacji.
W przypadku tego atrybutu dozwolony jest identyfikator zasobu w postaci ciągu znaków.
viewStreamItemActivity
- Pełna nazwa klasy aktywności w aplikacji, którą uruchamia aplikacja Kontakty na urządzeniu, gdy użytkownik kliknie element strumienia dla nieprzetworzonego kontaktu.
viewStreamItemPhotoActivity
- Pełna nazwa klasy działania w aplikacji, którą uruchamia aplikacja kontaktów na urządzeniu, gdy użytkownik kliknie zdjęcie w elemencie strumienia dla nieprzetworzonego kontaktu.
<ContactsDataKind> element
Element <ContactsDataKind>
steruje wyświetlaniem danych aplikacji
niestandardowe wiersze danych w interfejsie użytkownika aplikacji do obsługi kontaktów. Ma taką składnię:
<ContactsDataKind android:mimeType="MIMEtype" android:icon="icon_resources" android:summaryColumn="column_name" android:detailColumn="column_name">
zawarte w:
<ContactsAccountType>
Opis:
Użyj tego elementu, aby aplikacja kontaktów wyświetlała zawartość niestandardowego wiersza danych jako
który jest częścią surowego kontaktu. Każdy element podrzędny <ContactsDataKind>
wartości <ContactsAccountType>
reprezentuje typ niestandardowego wiersza danych, który jest synchronizowany
dodaje adapter do tabeli ContactsContract.Data
. Dodaj po jednym elemencie
<ContactsDataKind>
dla każdego używanego niestandardowego typu MIME. Nie masz
aby dodać element, jeśli masz niestandardowy wiersz danych, w którym nie chcesz wyświetlać danych.
Atrybuty:
android:mimeType
- Niestandardowy typ MIME zdefiniowany dla jednego z typów niestandardowych wierszy danych w tabeli
ContactsContract.Data
. Na przykład wartośćvnd.android.cursor.item/vnd.example.locationstatus
może być niestandardowym Typ MIME dla wiersza danych rejestrującego ostatnią znaną lokalizację kontaktu. android:icon
- Plik zasobów graficznych na Androida, który aplikacja Kontakty wyświetla obok Twoich danych. Użyj tego, aby wskazać użytkownikowi, że dane pochodzą z Twojej usługi.
android:summaryColumn
- Nazwa kolumny z pierwszą z 2 wartości wyodrębnionych z wiersza danych. jest wyświetlana jako pierwszy wiersz wpisu tego wiersza danych. Pierwszy wiersz służy do podsumowania danych, ale nie jest wymagany. Zobacz też android:detailColumn.
android:detailColumn
-
Nazwa kolumny dla drugiej z 2 wartości pobranych z wiersza danych. Wartość jest wyświetlana jako drugi wiersz wpisu w przypadku tego wiersza danych. Zobacz też
android:summaryColumn
.
Dodatkowe funkcje dostawcy kontaktów
Oprócz głównych funkcji opisanych w poprzednich sekcjach Dostawca kontaktów oferuje te przydatne funkcje do pracy z danymi kontaktów:
- Grupy kontaktów
- Funkcje związane ze zdjęciami
Grupy kontaktów
Dostawca kontaktów może opcjonalnie oznaczać zbiory powiązanych kontaktów za pomocą danych grupy. Jeśli serwer powiązany z kontem użytkownika
chce utrzymywać grupy, adapter synchronizacji dla konta typu konta powinien przenieść
grupuje dane między dostawcą kontaktów a serwerem. Gdy użytkownicy dodają nowego kontaktu na serwerze, a następnie umieszczają go w nowej grupie, adapter synchronizacji musi dodać nową grupę do tabeli ContactsContract.Groups
. Grupy, do których należy dany kontakt, są przechowywane w tabeli ContactsContract.Data
przy użyciu typu MIME ContactsContract.CommonDataKinds.GroupMembership
.
Jeśli projektujesz adapter synchronizacji, który dodaje nieprzetworzone dane kontaktów z
z dostawcą kontaktów, a nie korzystasz z grup, musisz przekazać
Dostawca, aby Twoje dane były widoczne. W kodzie, który jest wykonywany, gdy użytkownik dodaje konto do urządzenia, zaktualizuj wiersz ContactsContract.Settings
, który dostawca kontaktów dodaje do tego konta. W tym wierszu ustaw wartość kolumny
Settings.UNGROUPED_VISIBLE
na 1. W takim przypadku dostawca kontaktów będzie zawsze
udostępniać dane kontaktów, nawet jeśli nie używasz grup.
Zdjęcia kontaktów
Tabela ContactsContract.Data
przechowuje zdjęcia jako wiersze z typem MIME Photo.CONTENT_ITEM_TYPE
. Wartość wiersza
Kolumna CONTACT_ID
jest połączona z
_ID
nieprzetworzonego kontaktu, do którego należy ten kontakt.
Klasa ContactsContract.Contacts.Photo
definiuje podtabelę
ContactsContract.Contacts
z informacjami o zdjęciu kontaktu
główne, czyli podstawowe zdjęcie głównej osoby kontaktowej kontaktu. Podobnie klasa ContactsContract.RawContacts.DisplayPhoto
definiuje podtabelę ContactsContract.RawContacts
, która zawiera informacje o głównym zdjęciu nieprzetworzonego kontaktu.
Dokumentacja referencyjna funkcji ContactsContract.Contacts.Photo
i ContactsContract.RawContacts.DisplayPhoto
zawiera przykłady pobierania informacji o zdjęciach. Nie ma klasy ułatwiającej pobieranie miniatury głównej dla nieprzetworzonego kontaktu, ale możesz wysłać zapytanie do tabeli ContactsContract.Data
, wybierając kolumny _ID
, Photo.CONTENT_ITEM_TYPE
i IS_PRIMARY
, aby znaleźć wiersz głównego zdjęcia nieprzetworzonego kontaktu.
Dane z strumenienia społecznościowego dotyczące danej osoby mogą też zawierać zdjęcia. Są one przechowywane w tabeli android.provider.ContactsContract.StreamItemPhotos, która została opisana bardziej Szczegółowy opis znajdziesz w sekcji Zdjęcia w strumieniach społecznościowych.