"مقدِّم جهات الاتصال" هو أحد مكونات Android الفعّالة والمرنة التي تدير مستودع الجهاز المركزي للبيانات حول الأشخاص. "مقدِّم جهات الاتصال" هو مصدر البيانات التي تظهر لك في تطبيق جهات الاتصال على الجهاز، ويمكنك أيضًا الوصول إلى بياناته في تطبيقك ونقل البيانات بين الجهاز والخدمات على الإنترنت. ويستوعب مقدّم الخدمة مجموعة كبيرة من مصادر البيانات ويحاول إدارة أكبر قدر ممكن من البيانات لكل شخص، ما يؤدّي إلى تعقيد المؤسسة. ولهذا السبب، تتضمن واجهة برمجة التطبيقات لدى الموفّر مجموعة كبيرة من فئات العقود والواجهات التي تسهّل استرجاع البيانات وتعديلها.
يوضِّح هذا الدليل ما يلي:
- البنية الأساسية لمزود الخدمة.
- كيفية استرداد البيانات من مقدّم الخدمة
- كيفية تعديل البيانات في مقدّم الخدمة
- طريقة كتابة محوّل مزامنة لمزامنة البيانات من الخادم مع "مزوّد جهات الاتصال".
يفترض هذا الدليل أنّك على دراية بأساسيات موفّري محتوى Android. للحصول على مزيد من المعلومات حول موفّري المحتوى على أجهزة Android، يُرجى قراءة دليل أساسيات موفِّر المحتوى.
مؤسسة مقدّم جهات الاتصال
موفر جهات الاتصال هو أحد مكوّنات مزود خدمة محتوى Android. ويحتفظ هذا النظام بثلاثة أنواع من البيانات حول شخص، يتوافق كل منها مع جدول يقدّمه مقدّم الخدمة، على النحو الموضّح في الشكل 1:
![](https://developer.android.com/static/images/providers/contacts_structure.png?authuser=5&hl=ar)
الشكل 1. بنية جدول "مزوّد جهات الاتصال"
يشار إلى الجداول الثلاثة عادةً بأسماء فئات العقود الخاصة بها. وتحدّد الفئات الثوابت لمعرّفات الموارد المنتظمة (URI) للمحتوى وأسماء الأعمدة وقيم الأعمدة التي تستخدمها الجداول:
-
جدول "
ContactsContract.Contacts
" - الصفوف التي تمثل أشخاصًا مختلفين، استنادًا إلى تجميعات صفوف جهات الاتصال الأولية.
-
جدول "
ContactsContract.RawContacts
" - الصفوف التي تحتوي على ملخص لبيانات مستخدم خاص بحساب المستخدم ونوعه.
-
جدول "
ContactsContract.Data
" - الصفوف التي تحتوي على تفاصيل جهة الاتصال الأولية، مثل عناوين البريد الإلكتروني أو أرقام الهواتف.
الجداول الأخرى التي تمثّلها فئات العقود في ContactsContract
هي جداول إضافية يستخدمها "مقدِّم خدمة جهات الاتصال" لإدارة عملياته أو لإتاحة وظائف معيّنة في جهات اتصال الجهاز أو التطبيقات الهاتفية.
جهات الاتصال الأولية
تمثل جهة الاتصال الأولية بيانات الشخص الواردة من نوع حساب واسم حساب واحد. ولأنّ "مقدِّم جهات الاتصال" يسمح بأكثر من خدمة واحدة على الإنترنت كمصدر للبيانات لأحد الأشخاص، يسمح "مقدِّم جهات الاتصال" بعدة جهات اتصال أولية للمستخدم نفسه. وتسمح أيضًا جهات الاتصال الأولية المتعددة للمستخدم بدمج بيانات المستخدم من أكثر من حساب واحد من نوع الحساب نفسه.
لا يتم تخزين معظم بيانات جهة الاتصال الأولية في جدول
ContactsContract.RawContacts
. بدلاً من ذلك، يتم تخزينها في صف واحد أو أكثر
في جدول ContactsContract.Data
. يحتوي كل صف بيانات على عمود
Data.RAW_CONTACT_ID
يحتوي على القيمة RawContacts._ID
للصف ContactsContract.RawContacts
الرئيسي.
أعمدة جهات الاتصال الأولية المهمة
يتم عرض الأعمدة المهمة في الجدول ContactsContract.RawContacts
في الجدول 1. يُرجى قراءة الملاحظات التالية بعد الجدول:
الجدول 1. أعمدة جهات الاتصال الأولية المهمة.
اسم العمود | استخدام | Notes |
---|---|---|
ACCOUNT_NAME
|
اسم الحساب لنوع الحساب الذي يشكّل مصدر جهة الاتصال الأولية هذه.
على سبيل المثال، اسم حساب Google هو أحد عناوين Gmail لمالك الجهاز. راجِع الإدخال التالي الخاص بسمة ACCOUNT_TYPE للاطّلاع على مزيد من المعلومات.
|
ويكون تنسيق هذا الاسم خاصًا بنوع حسابه. وليس بالضرورة عنوان بريد إلكتروني. |
ACCOUNT_TYPE
|
نوع الحساب الذي يشكّل مصدر جهة الاتصال الأولية هذه. على سبيل المثال، نوع الحساب الخاص بحساب Google هو com.google . احرص دائمًا على تأهيل نوع حسابك
باستخدام معرّف نطاق لنطاق تملكه أو تتحكّم فيه. سيضمن ذلك أن يكون نوع حسابك فريدًا.
|
عادةً ما يكون لنوع الحساب الذي يقدم بيانات جهات الاتصال محوّل مزامنة مقترن يتزامن مع "مقدِّم جهات الاتصال". |
DELETED
|
علامة "محذوفة" لجهة اتصال أولية. | تسمح هذه العلامة لموفّر جهات الاتصال بالاحتفاظ بالصف داخليًا إلى أن تتمكن محوّلات المزامنة من حذف الصف من الخوادم ثم حذف الصف من المستودع في النهاية. |
Notes
في ما يلي ملاحظات مهمة حول جدول
"ContactsContract.RawContacts
":
-
لا يتم تخزين اسم جهة الاتصال الأولية في صفها في
ContactsContract.RawContacts
. بدلاً من ذلك، يتم تخزينها في جدولContactsContract.Data
في صفContactsContract.CommonDataKinds.StructuredName
. تحتوي جهة الاتصال الأولية على صف واحد فقط من هذا النوع في جدولContactsContract.Data
. -
تنبيه: لاستخدام بيانات حسابك في صف أولي لجهة اتصال، يجب أولاً أن يكون مسجَّلاً في
AccountManager
. ولإجراء ذلك، اطلب من المستخدمين إضافة نوع الحساب واسم حساباتهم إلى قائمة الحسابات. في حال عدم تنفيذ هذا الإجراء، سيحذف "مقدِّم جهات الاتصال" تلقائيًا صف جهات الاتصال الأولية.على سبيل المثال، إذا كنت تريد من تطبيقك الاحتفاظ ببيانات جهات الاتصال للخدمة المستنِدة إلى الويب باستخدام النطاق
com.example.dataservice
، وكان حساب المستخدم لخدمتك هوbecky.sharp@dataservice.example.com
، على المستخدم أولاً إضافة "نوع" الحساب (com.example.dataservice
) واسم الحساب (becky.smart@dataservice.example.com
) قبل أن يتمكّن تطبيقك من إضافة صفوف جهات الاتصال الأولية. يمكنك توضيح هذا الشرط للمستخدم في المستندات، أو يمكنك الطلب من المستخدم إضافة النوع والاسم أو كليهما. يتم توضيح أنواع الحسابات وأسماء الحسابات بمزيد من التفاصيل في القسم التالي.
مصادر بيانات جهات الاتصال الأولية
لفهم آلية عمل جهات الاتصال الأولية، فكِّر في المستخدم "Emily Dickinson" التي تم تحديد حسابات المستخدمين الثلاثة التالية على جهازها:
emily.dickinson@gmail.com
emilyd@gmail.com
- حساب Twitter "belle_of_amherst"
فعَّل هذا المستخدم مزامنة جهات الاتصال لهذه الحسابات الثلاثة في إعدادات الحسابات.
لنفترض أنّ إميلي ديكنسون فتحت نافذة متصفّح، وتسجّل الدخول إلى Gmail باسم
emily.dickinson@gmail.com
، وتفتح
"جهات الاتصال"، وأضافت "توماس هيغنسون". وفي وقت لاحق، سجّلت الدخول إلى Gmail باسم
emilyd@gmail.com
وأرسلت رسالة إلكترونية إلى "توماس هيغينسون" التي تضيفه تلقائيًا كجهة اتصال. وتتابع أيضًا "colonel_tom" (رقم تعريف Thomas Higginson على Twitter) على Twitter.
يقوم موفر جهات الاتصال بإنشاء ثلاث جهات اتصال أولية نتيجة لهذا العمل:
-
جهة اتصال أولية لـ "Thomas Higginson" المرتبطة بـ
emily.dickinson@gmail.com
نوع حساب المستخدم هو Google. -
جهة اتصال أولية ثانية لـ "Thomas Higginson" المرتبطة بـ
emilyd@gmail.com
نوع حساب المستخدم هو Google أيضًا. هناك جهة اتصال أولية ثانية على الرغم من أنّ الاسم مطابق لاسم سابق، لأنّه تمت إضافة المستخدم إلى حساب مستخدم آخر. - جهة اتصال أولية ثالثة لـ "Thomas Higginson" المرتبطة بـ "belle_of_amherst" ونوع حساب المستخدم هو Twitter.
البيانات
كما ذكرنا سابقًا، يتم تخزين بيانات جهة الاتصال الأولية في صف ContactsContract.Data
مرتبط بقيمة _ID
لجهة الاتصال الأولية. ويتيح ذلك لجهة اتصال أولية واحدة الحصول على مثيلات متعددة من النوع نفسه من البيانات، مثل عناوين البريد الإلكتروني أو أرقام الهواتف. على سبيل المثال، إذا كان "Thomas Higginson" لـ emilyd@gmail.com
(صف جهات الاتصال الأولى لـ Thomas Higginson المرتبط بحساب Google emilyd@gmail.com
) يتضمن عنوان بريد إلكتروني للمنزل thigg@gmail.com
وعنوان بريد إلكتروني للعمل هو thomas.higginson@gmail.com
، يخزِّن "مقدِّم خدمة جهات الاتصال" صفي عنوان البريد الإلكتروني ويربطهما بجهة الاتصال الأولية.
لاحظ أنه يتم تخزين أنواع مختلفة من البيانات في هذا الجدول المفرد. إنّ صفوف الاسم المعروض
ورقم الهاتف والبريد الإلكتروني والعنوان البريدي والصورة وتفاصيل الموقع الإلكتروني تتوفر كلها في جدول
ContactsContract.Data
. للمساعدة في إدارة ذلك، يحتوي الجدول
ContactsContract.Data
على بعض الأعمدة ذات الأسماء الوصفية،
بينما يحتوي البعض الآخر على أسماء عامة. ويكون لمحتويات عمود الاسم الوصفي المعنى نفسه
بغض النظر عن نوع البيانات في الصف، في حين يكون لمحتوى عمود الاسم العام
معانٍ مختلفة بناءً على نوع البيانات.
أسماء الأعمدة الوصفية
في ما يلي بعض الأمثلة على أسماء الأعمدة الوصفية:
-
RAW_CONTACT_ID
-
قيمة العمود
_ID
لجهة الاتصال الأولية لهذه البيانات. -
MIMETYPE
-
نوع البيانات المخزَّنة في هذا الصف، ويتم التعبير عنها بنوع MIME مخصّص. يستخدم "مقدِّم جهات الاتصال" أنواع MIME المحدّدة في الفئات الفرعية من
ContactsContract.CommonDataKinds
. وتُعد أنواع MIME هذه مفتوحة المصدر، ويمكن استخدامها من خلال أي تطبيق أو محوّل مزامنة يعمل مع "موفِّر خدمة جهات الاتصال". -
IS_PRIMARY
-
إذا كان من الممكن أن يحدث هذا النوع من صف البيانات أكثر من مرة لجهة اتصال أولية، سيشير
العمود
IS_PRIMARY
إلى صف البيانات الذي يحتوي على البيانات الأساسية لهذا النوع. على سبيل المثال، إذا ضغط المستخدم مع الاستمرار على رقم هاتف لجهة اتصال واخترت ضبط كتلقائي، سيتم ضبط العمودContactsContract.Data
الذي يحتوي على هذا الرقم علىIS_PRIMARY
على قيمة غير صفرية.
أسماء الأعمدة العامة
يتوفر بشكل عام 15 عمودًا عامًا يحمل اسم DATA1
إلى DATA15
، بالإضافة إلى أربعة أعمدة عامة إضافية من SYNC1
إلى SYNC4
لا يمكن استخدامها إلا عن طريق محوّلات المزامنة. تعمل الثوابت في اسم العمود العام دائمًا، بغض النظر عن نوع البيانات التي يحتوي عليها الصف.
تمت فهرسة عمود "DATA1
". يستخدم "مقدِّم جهات الاتصال" هذا العمود دائمًا للبيانات التي يتوقع مقدِّم الخدمة أن تكون الهدف الأكثر تكرارًا لطلب البحث. على سبيل المثال،
في صف الرسائل الإلكترونية، يحتوي هذا العمود على عنوان البريد الإلكتروني الفعلي.
حسب الاصطلاح، يتم حجز العمود DATA15
لتخزين بيانات الكائن الثنائي الكبير (BLOB) مثل الصور المصغّرة للصور.
أسماء الأعمدة الخاصة بالنوع
لتسهيل العمل على الأعمدة لنوع معيّن من الصفوف، يوفّر "مقدِّم جهات الاتصال" أيضًا ثوابت أسماء العمود الخاصة بنوع معيّن، والتي تم تحديدها في الفئات الفرعية من
ContactsContract.CommonDataKinds
. تعطي الثوابت ببساطة اسمًا ثابتًا مختلفًا لاسم العمود نفسه، ما يساعدك في الوصول إلى البيانات في صف من نوع معيّن.
على سبيل المثال، تحدّد الفئة ContactsContract.CommonDataKinds.Email
الثوابت الخاصة باسم العمود الخاص بالنوع لصف ContactsContract.Data
يتضمّن النوع MIME Email.CONTENT_ITEM_TYPE
. وتحتوي الفئة على ADDRESS
الثابت لعمود عنوان البريد الإلكتروني. القيمة الفعلية للسمة ADDRESS
هي "data1"، وهي
القيمة نفسها للاسم العام للعمود.
تنبيه: لا تضِف بياناتك المخصّصة إلى جدول
ContactsContract.Data
باستخدام صف يحتوي على أحد
أنواع MIME المحدّدة مسبقًا لموفّر الخدمة. إذا حدث ذلك، قد تفقد البيانات أو تتسبب في
تعطُّل المزوِّد. على سبيل المثال، يجب عدم إضافة صف من النوع MIME
Email.CONTENT_ITEM_TYPE
يحتوي على اسم مستخدم بدلاً من عنوان بريد إلكتروني في
العمود DATA1
. إذا كنت تستخدم نوع MIME المخصص الخاص بك للصف، يمكنك تحديد أسماء الأعمدة الخاصة بالنوع واستخدام الأعمدة كيفما تشاء.
يوضّح الشكل 2 كيفية ظهور الأعمدة الوصفية وأعمدة البيانات في
صف ContactsContract.Data
، وكيف "تراكب" أسماء الأعمدة الخاصة بالنوع
أسماء الأعمدة العامة
![كيفية تعيين أسماء الأعمدة الخاصة بالنوع إلى أسماء الأعمدة العامة](https://developer.android.com/static/images/providers/data_columns.png?authuser=5&hl=ar)
الشكل 2. أسماء الأعمدة الخاصة بالنوع وأسماء الأعمدة العامة.
فئات أسماء الأعمدة الخاصة بالنوع
يسرد الجدول 2 فئات أسماء الأعمدة الخاصة بالنوع الأكثر استخدامًا:
الجدول 2. فئات أسماء الأعمدة الخاصة بالنوع
صف رسم الخرائط | نوع البيانات | Notes |
---|---|---|
ContactsContract.CommonDataKinds.StructuredName |
بيانات الاسم لجهة الاتصال الأولية المرتبطة بصف البيانات هذا. | تحتوي جهة الاتصال الأولية على صف واحد فقط من هذه الصفوف. |
ContactsContract.CommonDataKinds.Photo |
الصورة الرئيسية لجهة الاتصال الأولية المرتبطة بصف البيانات هذا. | تحتوي جهة الاتصال الأولية على صف واحد فقط من هذه الصفوف. |
ContactsContract.CommonDataKinds.Email |
عنوان البريد الإلكتروني لجهة الاتصال الأولية المرتبطة بصف البيانات هذا. | يمكن أن يكون لجهة الاتصال الأولية عناوين بريد إلكتروني متعددة. |
ContactsContract.CommonDataKinds.StructuredPostal |
عنوان بريدي لجهة الاتصال الأولية المرتبطة بصف البيانات هذا. | يمكن أن يكون لجهة الاتصال الأولية عناوين بريدية متعددة. |
ContactsContract.CommonDataKinds.GroupMembership |
معرّف يربط جهة الاتصال الأولية بإحدى المجموعات في "موفر جهات الاتصال". | المجموعات هي ميزة اختيارية في نوع الحساب واسم الحساب. يتم توضيحها بمزيد من التفاصيل في قسم مجموعات جهات الاتصال. |
جهات الاتصال
يدمج "مقدِّم جهات الاتصال" صفوف جهات الاتصال الأولية في جميع أنواع الحسابات وأسماء الحسابات لتكوين جهة اتصال. يسهّل ذلك عرض وتعديل جميع البيانات التي جمعها المستخدم لشخص ما. يدير مزوّد جهات الاتصال إنشاء صفوف جهات اتصال جديدة وتجميع جهات الاتصال الأولية مع صف جهات الاتصال الحالي. لا يُسمح للتطبيقات أو محوّلات المزامنة بإضافة جهات اتصال، وبعض الأعمدة في صف جهة الاتصال تكون للقراءة فقط.
ملاحظة: إذا حاولت إضافة جهة اتصال إلى مقدِّم جهات الاتصال باستخدام
insert()
، ستحصل على استثناء
UnsupportedOperationException
. وإذا حاولت تعديل عمود
تم إدراجه على أنّه "للقراءة فقط"، سيتم تجاهل التعديل.
ينشئ "مقدِّم جهات الاتصال" جهة اتصال جديدة استجابةً لإضافة جهة اتصال أولية جديدة لا تتطابق مع أي جهات اتصال حالية. وينفّذ مقدّم الخدمة هذا الإجراء أيضًا في حال تغيّرت بيانات جهة اتصال أولية حالية بطريقة تؤدي إلى عدم تطابقها مع جهة الاتصال التي تم إرفاقها بها في السابق. إذا أنشأ تطبيق أو محوّل مزامنة جهة اتصال أولية جديدة تتطابق مع جهة اتصال حالية، يتم تجميع جهة الاتصال الأولية الجديدة مع جهة الاتصال الحالية.
يربط "مقدِّم جهات الاتصال" صفًا لجهة اتصال بصفوف جهات الاتصال الأوليّة باستخدام عمود
_ID
لصف جهات الاتصال في الجدول Contacts
. يحتوي العمود CONTACT_ID
في جدول جهات الاتصال الأولية ContactsContract.RawContacts
على _ID
من القيم لصف جهات الاتصال المرتبط بكل صف من صفوف جهات الاتصال الأولية.
يحتوي الجدول ContactsContract.Contacts
أيضًا على العمود LOOKUP_KEY
، وهو رابط "دائم" يؤدي إلى صف جهة الاتصال. ولأنّ "مزوِّد جهات الاتصال" يحافظ على جهات الاتصال
تلقائيًا، قد يغيّر قيمة _ID
لصف جهة الاتصال
استجابةً لعملية تجميع أو مزامنة. وحتى في حال حدوث ذلك، فإنّ معرّف الموارد المنتظم (URI) للمحتوى
CONTENT_LOOKUP_URI
الذي تم دمجه مع
عنوان LOOKUP_KEY
الخاص بجهة الاتصال سيظلّ
يشير إلى صف جهة الاتصال، وبالتالي يمكنك استخدام
LOOKUP_KEY
للاحتفاظ بالروابط المؤدية إلى جهات الاتصال "المفضّلة" وما إلى ذلك. ويكون لهذا العمود تنسيق خاص به غير مرتبط بتنسيق عمود "_ID
".
يوضح الشكل 3 كيفية ارتباط الجداول الرئيسية الثلاثة ببعضها البعض.
![الجداول الرئيسية لمزوِّدي جهات الاتصال](https://developer.android.com/static/images/providers/contacts_tables.png?authuser=5&hl=ar)
الشكل 3. علاقات جدول "جهات الاتصال" و"جهات الاتصال الأولية" و"التفاصيل"
تنبيه: إذا نشرت تطبيقك على "متجر Google Play" أو كان تطبيقك على جهاز يعمل بإصدار Android 10 (المستوى 29 من واجهة برمجة التطبيقات) أو إصدار أحدث، يُرجى العِلم أنّ هناك مجموعة محدودة من حقول بيانات جهات الاتصال وطرقها قديمة.
في إطار الشروط المذكورة، يمحو النظام بشكل دوري أي قيم مكتوبة في حقول البيانات التالية:
-
ContactsContract.ContactOptionsColumns.LAST_TIME_CONTACTED
-
ContactsContract.ContactOptionsColumns.TIMES_CONTACTED
-
ContactsContract.DataUsageStatColumns.LAST_TIME_USED
-
ContactsContract.DataUsageStatColumns.TIMES_USED
واجهات برمجة التطبيقات المستخدمة لإعداد حقول البيانات أعلاه هي أيضًا قديمة:
وبالإضافة إلى ذلك، لم تعد الحقول التالية تعرض جهات اتصال متكررة. يُرجى العلم بأنّ بعض هذه الحقول لا تؤثر في ترتيبات جهات الاتصال إلا عندما تكون جهات الاتصال جزءًا من نوع بيانات معيّن.
-
ContactsContract.Contacts.CONTENT_FREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_FILTER_URI
-
CONTENT_FILTER_URI
(يؤثر فقط في أنواع بيانات البريد الإلكتروني والهاتف والأجهزة التي يمكن الاتصال بها وإمكانية التواصل ) -
ENTERPRISE_CONTENT_FILTER_URI
(يؤثر فقط في أنواع بيانات البريد الإلكتروني والهاتف وإمكانية الاتصال )
في حال وصول تطبيقاتك إلى هذه الحقول أو واجهات برمجة التطبيقات أو تعديلها، يمكنك استخدام طرق بديلة. على سبيل المثال، يمكنك تنفيذ حالات استخدام معيّنة باستخدام موفّري المحتوى الخاص أو البيانات الأخرى المخزَّنة داخل تطبيقك أو أنظمة الخلفية.
للتأكّد من أنّ وظائف تطبيقك لا تتأثر بهذا التغيير، يمكنك محو حقول البيانات هذه يدويًا. ولإجراء ذلك، شغِّل أمر ADB التالي على جهاز يعمل بنظام التشغيل Android 4.1 (المستوى 16 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث:
adb shell content delete \ --uri content://com.android.contacts/contacts/delete_usage
البيانات الواردة من محوّلات المزامنة
يُدخِل المستخدمون بيانات جهات الاتصال مباشرةً في الجهاز، ولكن تتدفق البيانات أيضًا إلى "مقدِّم جهات الاتصال" من خدمات الويب عبر محوّلات المزامنة التي تعمل على نقل البيانات بين الجهاز والخدمات تلقائيًا. تعمل محوّلات المزامنة في الخلفية
تحت تحكّم النظام، وهي تستدعي طُرق ContentResolver
لإدارة البيانات.
في نظام التشغيل Android، يتم تحديد خدمة الويب التي يعمل معها محوِّل المزامنة من خلال نوع الحساب. يعمل كل محوّل مزامنة مع نوع حساب واحد، ولكنّه يمكن أن يتوافق مع أسماء حسابات متعددة لهذا النوع. يتم توضيح أنواع الحسابات وأسماء الحسابات بإيجاز في القسم مصادر بيانات جهات الاتصال الأولية. تقدّم التعريفات التالية مزيدًا من التفاصيل وتوضّح العلاقة بين نوع الحساب واسمه بمحوّلات المزامنة والخدمات.
- نوع الحساب
-
تُحدِّد الخدمة الخدمة التي خزّن المستخدم البيانات فيها. وفي معظم الأحيان، يحتاج المستخدم إلى
المصادقة باستخدام الخدمة. على سبيل المثال، "جهات اتصال Google" هي نوع حساب يتم تحديده باستخدام الرمز
google.com
. تتوافق هذه القيمة مع نوع الحساب الذي يستخدمهAccountManager
. - اسم الحساب
- يحدّد حسابًا معيّنًا أو معلومات تسجيل دخول لنوع حساب معيّن. حسابات "جهات اتصال Google" هي نفسها حسابات Google التي يكون لها عنوان بريد إلكتروني كاسم حساب. قد تستخدم الخدمات الأخرى اسم مستخدم من كلمة واحدة أو معرّف رقمي.
لا يلزم أن تكون أنواع الحسابات فريدة. يمكن للمستخدم إعداد حسابات متعددة في "جهات اتصال Google" وتنزيل بياناته إلى "مقدِّم جهات الاتصال"، وقد يحدث ذلك إذا كان المستخدم لديه مجموعة واحدة من جهات الاتصال الشخصية لاسم حساب شخصي ومجموعة أخرى للعمل. وتكون أسماء الحسابات عادةً فريدة. ويحدِّدان معًا تدفق بيانات محددًا بين "مقدِّم جهات الاتصال" وخدمة خارجية.
إذا أردت نقل بيانات الخدمة إلى "مقدِّم جهات الاتصال"، يجب كتابة محوّل المزامنة الخاص بك. يمكنك الاطّلاع على مزيد من التفاصيل في القسم محوّلات مزامنة مزوّد خدمة "جهات الاتصال".
يوضح الشكل 4 كيفية ملاءمة "مقدم خدمة جهات الاتصال" لتدفق البيانات المتعلقة بالأشخاص. في المربع الذي تم وضع علامة "محوّلات المزامنة" عليه، يتم تصنيف كل محوّل حسب نوع حسابه.
![تدفق البيانات حول الأشخاص](https://developer.android.com/static/images/providers/ContactsDataFlow.png?authuser=5&hl=ar)
الشكل 4. تدفق البيانات مع "مزوّد جهات الاتصال"
الأذونات المطلوبة
على التطبيقات التي تريد الوصول إلى "مقدِّم جهات الاتصال" طلب الأذونات التالية:
- الإذن بالاطّلاع على جدول واحد أو أكثر تم تحديد السمة
-
READ_CONTACTS
فيAndroidManifest.xml
مع العنصر<uses-permission>
على أنّها<uses-permission android:name="android.permission.READ_CONTACTS">
. - إذن الوصول للكتابة في جدول واحد أو أكثر تم تحديد السمة
-
WRITE_CONTACTS
فيAndroidManifest.xml
مع العنصر<uses-permission>
على أنّها<uses-permission android:name="android.permission.WRITE_CONTACTS">
.
لا تمتد هذه الأذونات إلى بيانات الملف الشخصي للمستخدم. ستتم مناقشة الملف الشخصي للمستخدم وأذوناته المطلوبة في القسم التالي: الملف الشخصي للمستخدم.
تذكر أن بيانات جهات اتصال المستخدم شخصية وحساسة. يشعر المستخدمون بالقلق بشأن خصوصيتهم، لذا لا يريدون التطبيقات التي تجمع بيانات عنهم أو عن جهات اتصالهم. وإذا لم تتضح سبب احتياجك إلى إذن للوصول إلى بيانات جهات الاتصال، قد يحصل تطبيقك على تقييمات منخفضة أو يرفض تثبيته.
الملف الشخصي للمستخدم
يتضمن الجدول ContactsContract.Contacts
صفًا واحدًا يحتوي على
بيانات الملف الشخصي لمستخدم الجهاز. تصف هذه البيانات user
في الجهاز بدلاً من
إحدى جهات اتصال المستخدم. يرتبط صف جهات اتصال الملف الشخصي بصف جهات اتصال أولية لكل نظام يستخدم ملفًا شخصيًا.
يمكن أن يحتوي كل صف لجهة اتصال أولية في الملف الشخصي على صفوف بيانات متعددة. تتوفّر محاولات للوصول إلى الملف الشخصي للمستخدم في الصف ContactsContract.Profile
.
يتطلب الوصول إلى الملف الشخصي للمستخدم أذونات خاصة. بالإضافة إلى الإذنَين READ_CONTACTS
وWRITE_CONTACTS
المطلوبَين للقراءة والكتابة، يجب منح الإذنَين android.Manifest.permission#READ_PROFILE وandroid.Manifest.permission#WRITE_PROFILE بالوصول إلى الملف الشخصي للقراءة والكتابة، وذلك على التوالي.
تذكر أنه يجب اعتبار الملف الشخصي للمستخدم حساسًا. يتيح لك الإذن android.Manifest.permission#READ_PROFILE إمكانية الوصول إلى البيانات التي تحدِّد الهوية الشخصية لمستخدم الجهاز. احرص في وصف تطبيقك على إخبار المستخدم بسبب الحاجة إلى أذونات الوصول إلى الملف الشخصي للمستخدم.
لاسترداد صف جهة الاتصال الذي يحتوي على الملف الشخصي للمستخدم،
اتصل بـ ContentResolver.query()
. اضبط معرّف الموارد المنتظم (URI) للمحتوى على
CONTENT_URI
بدون
أي معايير اختيار. يمكنك أيضًا استخدام معرّف الموارد المنتظم (URI) للمحتوى هذا باعتباره معرّف الموارد المنتظم (URI) الأساسي لاسترداد جهات الاتصال
أو البيانات الأوّلية للملف الشخصي. على سبيل المثال، يسترد هذا المقتطف بيانات الملف الشخصي:
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);
ملاحظة: إذا استرددت صفوف جهات اتصال متعددة وأردت تحديد ما إذا كان أحدها
هو الملف الشخصي للمستخدم، يمكنك اختبار عمود
IS_USER_PROFILE
للصف. ويتم ضبط هذا العمود على "1" إذا كانت جهة الاتصال هي الملف الشخصي للمستخدم.
البيانات الوصفية لمزوِّد جهات الاتصال
يدير "مقدِّم جهات الاتصال" البيانات التي تتتبّع حالة بيانات جهات الاتصال في المستودع. يتم تخزين هذه البيانات الوصفية حول المستودع في أماكن مختلفة، بما في ذلك صفوف جدول "جهات الاتصال الأولية" و"البيانات" و"جهات الاتصال" والجدول "ContactsContract.Settings
" وجدول "ContactsContract.SyncState
". يعرض الجدول التالي تأثير كلّ جزء من هذه الأجزاء من البيانات الوصفية:
الجدول 3. البيانات الوصفية في "مقدِّم جهات الاتصال"
جدول | العمود | القيم | المعنى |
---|---|---|---|
ContactsContract.RawContacts |
DIRTY |
"0" - لم يتم تغييره منذ آخر مزامنة. |
يضع علامة على جهات الاتصال الأولية التي تم تغييرها على الجهاز ويجب مزامنتها مرة أخرى مع
الخادم. يضبط "مقدِّم جهات الاتصال" القيمة تلقائيًا عندما تعدِّل تطبيقات Android أحد الصفوف.
إنّ محوّلات المزامنة التي تعدِّل جهات الاتصال أو جداول البيانات الأولية يجب أن تُلحق دائمًا السلسلة |
"1" - تم تغييره منذ آخر مزامنة، ويجب مزامنته مرة أخرى مع الخادم. | |||
ContactsContract.RawContacts |
VERSION |
رقم إصدار هذا الصف. | ويعمل "مقدِّم جهات الاتصال" على زيادة هذه القيمة تلقائيًا كلما تغير الصف أو البيانات ذات الصلة به. |
ContactsContract.Data |
DATA_VERSION |
رقم إصدار هذا الصف. | ويعمل "مقدِّم جهات الاتصال" على زيادة هذه القيمة تلقائيًا كلما تم تغيير صف البيانات. |
ContactsContract.RawContacts |
SOURCE_ID |
قيمة سلسلة تحدِّد جهة الاتصال الأولية هذه بشكلٍ فريد للحساب الذي تم إنشاؤها فيه. |
عندما ينشئ محوّل المزامنة جهة اتصال أولية جديدة، يجب ضبط هذا العمود على
المعرّف الفريد للخادم لجهة الاتصال الأولية. عندما ينشئ تطبيق Android جهة اتصال أولية جديدة، يجب أن يترك التطبيق هذا العمود فارغًا. يؤدي ذلك إلى إرسال إشارة إلى محوّل المزامنة بأنّه يجب أن ينشئ جهة اتصال أولية جديدة على الخادم، ويحصل على قيمة SOURCE_ID .
وعلى وجه الخصوص، يجب أن يكون رقم تعريف المصدر فريدًا لكل نوع حساب، كما يجب أن يكون ثابتًا في جميع عمليات المزامنة:
|
ContactsContract.Groups |
GROUP_VISIBLE |
"0" - يجب ألا تظهر جهات الاتصال في هذه المجموعة في واجهات مستخدم تطبيقات Android. | هذا العمود مخصّص للتوافق مع الخوادم التي تسمح للمستخدم بإخفاء جهات الاتصال في مجموعات معيّنة. |
"1" - يتم السماح لجهات الاتصال في هذه المجموعة بالظهور في واجهات المستخدم للتطبيق. | |||
ContactsContract.Settings |
UNGROUPED_VISIBLE |
"0" - بالنسبة إلى هذا الحساب ونوع الحساب، تكون جهات الاتصال التي لا تنتمي إلى مجموعة غير مرئية لواجهات مستخدم تطبيقات Android. |
تكون جهات الاتصال غير مرئية تلقائيًا إذا لم تكن أي من جهات الاتصال الأولية تنتمي إلى مجموعة
(تتم الإشارة إلى عضوية المجموعة لجهة اتصال أولية من خلال صف ContactsContract.CommonDataKinds.GroupMembership واحد أو أكثر
في جدول ContactsContract.Data ).
من خلال ضبط هذه العلامة في صف الجدول "ContactsContract.Settings " لنوع الحساب وحساب، يمكنك فرض ظهور جهات الاتصال التي ليس لها مجموعات.
تتمثل إحدى استخدامات هذه العلامة في عرض جهات الاتصال من الخوادم التي لا تستخدم مجموعات.
|
"1" - بالنسبة إلى هذا الحساب ونوع الحساب، تكون جهات الاتصال التي لا تنتمي إلى مجموعة مرئية لواجهات مستخدم التطبيق. | |||
ContactsContract.SyncState |
(الكل) | يمكنك استخدام هذا الجدول لتخزين البيانات الوصفية لمحوّل المزامنة. | باستخدام هذا الجدول، يمكنك تخزين حالة المزامنة والبيانات الأخرى ذات الصلة بالمزامنة باستمرار على الجهاز. |
إذن الوصول إلى "مقدِّم جهات الاتصال"
يصف هذا القسم إرشادات الوصول إلى البيانات من "مقدِّم جهات الاتصال"، مع التركيز على ما يلي:
- طلبات البحث عن الكيانات
- التعديل المجمّع
- الاسترجاع والتعديل باستخدام الأغراض.
- سلامة البيانات.
ويتوفر أيضًا مزيد من التفاصيل في القسم محوّلات مزامنة موفِّر خدمة "جهات الاتصال" بشأن إجراء تعديلات باستخدام محوِّل المزامنة.
الاستعلام عن الكيانات
بما أنّ جداول "مزوّد جهات الاتصال" منظّمة في تسلسل هرمي، غالبًا ما يكون من المفيد استرداد صف وجميع الصفوف "الفرعية" المرتبطة به. على سبيل المثال، لعرض جميع المعلومات لمستخدم، قد تحتاج إلى استرداد جميع صفوف ContactsContract.RawContacts
لصف ContactsContract.Contacts
واحد، أو جميع صفوف ContactsContract.CommonDataKinds.Email
لصف ContactsContract.RawContacts
واحد. لتسهيل ذلك، يوفر موفِّر
جهات الاتصال بُنى entity، والتي تعمل كعمليات ضم قاعدة بيانات بين الجداول.
يشبه الكيان الجدول المكون من أعمدة محددة من جدول رئيسي وجدوله الفرعي.
عند طلب البحث عن كيان، يمكنك تقديم توقّع ومعايير بحث استنادًا إلى الأعمدة المتاحة من الكيان. والنتيجة هي Cursor
يحتوي على صف واحد لكل صف جدول فرعي تم استرداده. على سبيل المثال، إذا أجريت طلب بحث عن ContactsContract.Contacts.Entity
لاسم جهة اتصال وجميع صفوف ContactsContract.CommonDataKinds.Email
لجميع جهات الاتصال الأولية المرتبطة بهذا الاسم، ستحصل على حرف Cursor
يحتوي على صف واحد لكل صف ContactsContract.CommonDataKinds.Email
.
تعمل الكيانات على تبسيط طلبات البحث. باستخدام أحد الكيانات، يمكنك استرداد جميع بيانات جهات الاتصال لجهة اتصال أو جهة اتصال أولية في آنٍ واحد، بدلاً من الحاجة إلى إجراء طلب بحث في الجدول الرئيسي أولاً للحصول على رقم تعريف، ثم إجراء طلب بحث في الجدول الفرعي باستخدام رقم التعريف هذا. بالإضافة إلى ذلك، يعالج "مقدِّم جهات الاتصال" طلب بحث في أحد الكيانات في معاملة واحدة، ما يضمن أن تكون البيانات التي تم استردادها متسقة داخليًا.
ملاحظة: لا يحتوي الكيان عادةً على جميع أعمدة الجدول الرئيسي
والثانوي. إذا كنت تحاول العمل باستخدام اسم عمود غير مُدرَج في قائمة ثوابت اسم العمود الخاصة بالكيان، ستحصل على Exception
.
يعرض المقتطف التالي كيفية استرداد جميع صفوف جهات الاتصال الأولية لجهة اتصال. والمقتطف هو جزء من تطبيق أكبر يشتمل على نشاطين، هما "الرئيسي" و "التفاصيل". ويعرض النشاط الرئيسي
قائمة بصفوف جهات الاتصال. عندما يختار المستخدم إحدى الصفوف، يرسل النشاط رقم تعريفه إلى النشاط
التفصيلي. يستخدم نشاط التفاصيل ContactsContract.Contacts.Entity
لعرض جميع صفوف البيانات من جميع جهات الاتصال الأولية المرتبطة بجهة الاتصال المحددة.
هذا المقتطف مأخوذ من نشاط "التفاصيل":
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. }
عند انتهاء التحميل، يستدعي LoaderManager
معاودة الاتصال إلى
onLoadFinished()
. تمثّل إحدى الوسيطات الواردة إلى هذه الطريقة Cursor
التي تحتوي على نتائج طلب البحث. وفي تطبيقك الخاص، يمكنك الحصول على
البيانات من جهاز "Cursor
" هذا لعرضها أو العمل معه بشكل أكبر.
التعديل المجمّع
كلما أمكن، عليك إدراج البيانات في "مقدِّم جهات الاتصال" وتعديلها وحذفها في
"وضع الدفعة"، من خلال إنشاء ArrayList
من
كائنات ContentProviderOperation
واستدعاء
applyBatch()
. وبما أنّ
"مقدِّم جهات الاتصال" ينفِّذ جميع العمليات في
applyBatch()
في
عملية واحدة، لن تترك التعديلات التي تُجريها أبدًا مستودع جهات الاتصال
في حالة غير متّسقة. يسهّل التعديل المجمّع أيضًا إدراج جهة اتصال أولية وبيانات تفاصيلها
في الوقت نفسه.
ملاحظة: لتعديل جهة اتصال أولية واحدة، يمكنك إرسال هدف إلى تطبيق جهات الاتصال على الجهاز بدلاً من معالجة التعديل في تطبيقك. يمكنك الاطّلاع على مزيد من التفاصيل بخصوص إجراء ذلك في قسم الاسترجاع والتعديل باستخدام الأهداف.
النقاط المحقّقة
يمكن أن يؤدي التعديل المجمّع الذي يحتوي على عدد كبير من العمليات إلى حظر العمليات الأخرى،
ما يؤدي إلى ترك انطباع سيئ لدى المستخدم بشكل عام. لتنظيم جميع التعديلات التي تريد
إجراؤها في أقل عدد ممكن من القوائم المنفصلة، وفي الوقت نفسه منعها من
حظر النظام، عليك تحديد نقاط النتيجة لعملية واحدة أو أكثر.
نقطة العائد هي عنصر ContentProviderOperation
تم ضبط قيمته isYieldAllowed()
على true
. عندما يواجه "مقدِّم جهات الاتصال" نقطة تسليم، يتوقف عمله مؤقتًا للسماح بتشغيل العمليات الأخرى ويتم إغلاق المعاملة الحالية. عندما يبدأ مقدّم الخدمة عملية الشراء مجددًا، يبدأ
بالعملية التالية في ArrayList
ويبدأ معاملة
جديدة.
تؤدي النقاط المحقَّقة إلى إجراء أكثر من معاملة واحدة لكل اتصال بـ "applyBatch()
". لهذا السبب، يجب ضبط نقطة نتيجة للعملية الأخيرة لمجموعة من الصفوف ذات الصلة.
على سبيل المثال، يجب تحديد نقطة نتيجة للعملية الأخيرة في مجموعة تضيف صفوف جهات الاتصال الأولية وصفوف البيانات المرتبطة بها، أو قيمة العملية الأخيرة لمجموعة من الصفوف ذات الصلة بجهة اتصال واحدة.
تعتبر نقاط الجرعة أيضًا وحدة من العمليات الذرية. وستنجح جميع عمليات الوصول بين نقطتين من نقاط العائدات أو ستفشل كوحدة واحدة. في حال عدم تحديد أي نقاط حصيلة، ستكون أصغر عملية ذرية هي مجموعة العمليات بالكامل. وإذا كنت تستخدم نقاطًا، ستمنع العمليات من التأثير سلبًا في أداء النظام، مع ضمان أنّ مجموعة فرعية من العمليات شاملة.
مراجع الرجوع إلى التعديلات
عند إدراج صف جهة اتصال أولي جديد وصفوف البيانات المرتبطة به كمجموعة من
عناصر ContentProviderOperation
، عليك ربط صفوف البيانات
بصف جهة الاتصال الأوليّة عن طريق إدراج قيمة
_ID
لجهة الاتصال الأولية
على أنّها قيمة RAW_CONTACT_ID
. ولا تتوفّر هذه القيمة عند إنشاء ContentProviderOperation
لصف البيانات، لأنّك لم تطبّق بعد العنصر ContentProviderOperation
لصف جهة الاتصال الأولية. ولحلّ هذه المشكلة، تستخدم الصف ContentProviderOperation.Builder
الطريقة withValueBackReference()
.
تتيح لك هذه الطريقة إدراج أو تعديل عمود كنتيجة لعملية سابقة.
تتضمّن الطريقة withValueBackReference()
وسيطتَين هما:
-
key
- المفتاح لزوج المفتاح/القيمة. يجب أن تكون قيمة هذه الوسيطة اسم العمود في الجدول الذي تعدله.
-
previousResult
-
هو الفهرس المستند إلى 0 لقيمة في مصفوفة عناصر
ContentProviderResult
منapplyBatch()
. أثناء تطبيق العمليات المجمّعة، يتم تخزين نتيجة كل عملية في مصفوفة متوسطة من النتائج. وتُعدّ القيمةpreviousResult
فهرس إحدى هذه النتائج، ويتم استردادها وتخزينها باستخدام القيمةkey
. يتيح لك هذا الإجراء إدراج سجلّ جهات اتصال أولي جديد واستعادة قيمة_ID
الخاصة به، ثم إنشاء "مرجع رجوع" للقيمة عند إضافة صفContactsContract.Data
.يتم إنشاء مصفوفة النتائج بالكامل عند استدعاء
applyBatch()
لأول مرة، بحجم يساوي حجمArrayList
من عناصرContentProviderOperation
التي تقدمها. في المقابل، يتم ضبط جميع العناصر في مصفوفة النتيجة علىnull
، وإذا حاولت الرجوع إلى نتيجة لعملية لم يتم تطبيقها بعد، تؤديwithValueBackReference()
إلى طرحException
.
توضِّح المقتطفات التالية كيفية إدراج جهة اتصال أو بيانات أولية جديدة بشكل مجمّع. وهي تشمل رمزًا برمجيًا يؤسس نقطة إنتاجية وتستخدم مرجعًا خلفيًا.
يسترد المقتطف الأول بيانات جهة الاتصال من واجهة المستخدم. في هذه المرحلة، سبق أن اختار المستخدم الحساب الذي يجب إضافة جهة الاتصال الأولية الجديدة إليه.
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());
ينشئ المقتطف التالي عملية لإدراج صف جهات الاتصال الأولية في جدول 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());
بعد ذلك، يُنشئ الرمز صفوف بيانات لصفوف الاسم المعروض والهاتف والبريد الإلكتروني.
يستخدم كل عنصر من عناصر أداة إنشاء العمليات withValueBackReference()
للحصول على RAW_CONTACT_ID
. يشير المرجع إلى الكائن ContentProviderResult
من العملية الأولى، ما يضيف صف جهة الاتصال الأولي ويعرض قيمة _ID
الجديدة. نتيجةً لذلك، يتم تلقائيًا ربط كل صف بيانات من خلال
RAW_CONTACT_ID
بصف ContactsContract.RawContacts
الجديد الذي ينتمي إليه.
يتم وضع علامة withYieldAllowed()
على العنصر ContentProviderOperation.Builder
الذي يضيف صف البريد الإلكتروني، ما يحدِّد نقطة تسليم:
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());
يعرض المقتطف الأخير المكالمة إلى applyBatch()
التي تُدرج جهات الاتصال وصفوف البيانات الأولية الجديدة.
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); } }
وتتيح لك العمليات المجمّعة أيضًا تنفيذ التحكّم المتفائل في التزامن، وهي طريقة لتطبيق معاملات التعديل بدون الحاجة إلى قفل المستودع الأساسي. لاستخدام هذه الطريقة، يمكنك تطبيق المعاملة ثم البحث عن تعديلات أخرى يُحتمل أنّها تم إجراؤها في الوقت نفسه. وإذا لاحظت حدوث تعديل غير متسق، يمكنك التراجع عن المعاملة وإعادة المحاولة.
يُعد التحكم في التزامن المتفائل مفيدًا في الأجهزة الجوّالة، حيث يكون هناك مستخدم واحد فقط في كل مرة، وتكون عمليات الوصول المتزامنة إلى مستودع البيانات نادرة. وبسبب عدم استخدام هذه المفاتيح، لا يتم إضاعة أي وقت في ضبط الأقفال أو انتظار إجراء معاملات أخرى لفتح الأقفال.
لاستخدام عنصر التحكّم في التزامن بشكل متفائل أثناء تعديل صف ContactsContract.RawContacts
واحد، اتّبِع الخطوات التالية:
-
استرِد عمود
VERSION
لجهة الاتصال الأولية مع البيانات الأخرى التي تستردها. -
أنشِئ كائن
ContentProviderOperation.Builder
مناسبًا لفرض قيد باستخدام الطريقةnewAssertQuery(Uri)
. بالنسبة إلى معرّف الموارد المنتظم (URI) للمحتوى، استخدِمRawContacts.CONTENT_URI
مع إلحاق_ID
لجهة الاتصال الأولية به. -
بالنسبة إلى العنصر
ContentProviderOperation.Builder
، يمكنك استدعاءwithValue()
لمقارنة عمودVERSION
برقم الإصدار الذي تم استرداده للتو. -
بالنسبة إلى السمة
ContentProviderOperation.Builder
نفسها، يمكنك استدعاءwithExpectedCount()
للتأكد من اختبار صف واحد فقط من خلال هذا التأكيد. -
عليك استدعاء
build()
لإنشاء العنصرContentProviderOperation
، ثم إضافته باعتباره العنصر الأول فيArrayList
الذي تضبطه إلىapplyBatch()
. - طبِّق المعاملة المجمّعة.
إذا تم تعديل صف جهة الاتصال الأولية من خلال عملية أخرى بين وقت قراءة الصف
والوقت الذي تحاول فيه تعديله، سيتعذّر استخدام علامة ContentProviderOperation
"تأكيد" وسيتم الاحتفاظ بنسخة احتياطية من مجموعة العمليات بأكملها. يمكنك بعد ذلك اختيار إعادة محاولة
الدفعة أو اتخاذ بعض الإجراءات الأخرى.
يوضّح المقتطف التالي كيفية إنشاء ContentProviderOperation
"تأكيد" بعد إجراء طلب بحث عن جهة اتصال أولية واحدة باستخدام
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 }
الاسترجاع والتعديل باستخدام الأغراض
إنّ إرسال غرض إلى تطبيق جهات الاتصال في الجهاز يتيح لك الوصول إلى "مقدِّم جهات الاتصال" بشكل غير مباشر. يبدأ الغرض من واجهة مستخدم تطبيق "جهات الاتصال" على الجهاز، والتي يمكن للمستخدمين من خلالها تنفيذ العمل المرتبط بجهات الاتصال. من خلال هذا النوع من الوصول، يمكن للمستخدمين:
- اختر جهة اتصال من القائمة وأعدها إلى تطبيقك لإجراء المزيد من العمل.
- تعديل بيانات جهة اتصال حالية
- إدراج جهة اتصال أولية جديدة لأي من حساباتها.
- حذف جهة اتصال أو بيانات جهات الاتصال
إذا كان المستخدم يدرج بيانات أو يعدّلها، يمكنك جمع البيانات أولاً وإرسالها كجزء من الغرض.
عند استخدام أهداف للوصول إلى "مقدِّم جهات الاتصال" من خلال تطبيق جهات الاتصال على الجهاز، لن تحتاج إلى كتابة واجهة المستخدم أو الرمز الخاص بك للوصول إلى مقدّم الخدمة. ولن تضطر أيضًا إلى طلب إذن للقراءة أو الكتابة إلى مقدّم الخدمة. قد يفوّض تطبيق جهات الاتصال على الجهاز إذن القراءة لجهة الاتصال إليك، ولأنّك تجري تعديلات على مقدّم الخدمة من خلال تطبيق آخر، لن تحتاج إلى أذونات الكتابة.
يتم وصف العملية العامة لإرسال هدف الوصول إلى مقدّم الخدمة بالتفصيل في دليل
أساسيات موفِّر المحتوى ضمن القسم "الوصول إلى البيانات عبر الأغراض". في الجدول 4، يتم تلخيص الإجراء
ونوع MIME وقيم البيانات التي تستخدمها للمهام المتاحة، بينما
يتم تلخيص القيم الإضافية التي يمكنك استخدامها مع
putExtra()
في المستندات المرجعية لـ ContactsContract.Intents.Insert
:
الجدول 4. أغراض مقدِّمي خدمة جهات الاتصال
المهمة | الإجراء | البيانات | نوع MIME | Notes |
---|---|---|---|---|
اختيار جهة اتصال من قائمة | ACTION_PICK |
أحد الخيارات التالية:
|
غير مستخدَم |
يعرض قائمة بجهات الاتصال الأولية أو قائمة ببيانات من جهة اتصال أولية، استنادًا إلى نوع معرّف الموارد المنتظم (URI) للمحتوى الذي تقدمه.
يمكنك استدعاء
|
إدراج جهة اتصال أولية جديدة | Insert.ACTION |
لا ينطبق |
RawContacts.CONTENT_TYPE ، نوع MIME لمجموعة من جهات الاتصال الأولية.
|
يتم عرض شاشة إضافة جهة اتصال في تطبيق جهات الاتصال على الجهاز. ويتم عرض
القيم الإضافية التي تضيفها إلى الغرض. إذا تم إرساله باستخدام startActivityForResult() ، يتم إرسال معرّف الموارد المنتظم للمحتوى لجهة الاتصال الأولية التي تمت إضافتها حديثًا إلى طريقة معاودة الاتصال onActivityResult() الخاصة بنشاطك في الوسيطة Intent ضمن حقل "البيانات". لمعرفة القيمة، يمكنك طلب "getData() ".
|
تعديل جهة اتصال | ACTION_EDIT |
CONTENT_LOOKUP_URI
لجهة الاتصال. سيسمح نشاط المحرّر للمستخدم بتعديل أي من البيانات المرتبطة
بجهة الاتصال هذه.
|
Contacts.CONTENT_ITEM_TYPE ، جهة اتصال واحدة |
يعرض شاشة "تعديل جهة الاتصال" في تطبيق جهات الاتصال. ويتم عرض القيم الإضافية التي تضيفها إلى الغرض. عندما ينقر المستخدم على تم لحفظ التعديلات، يعود نشاطك إلى المقدّمة. |
عرض أداة اختيار يمكنها إضافة بيانات أيضًا | ACTION_INSERT_OR_EDIT |
لا ينطبق |
CONTENT_ITEM_TYPE
|
يعرض هذا الغرض دائمًا شاشة أداة اختيار تطبيق جهات الاتصال. ويمكن للمستخدم اختيار جهة اتصال لتعديلها أو إضافة جهة اتصال جديدة. ستظهر إما شاشة التعديل أو شاشة الإضافة، حسب اختيار المستخدم، وسيتم عرض البيانات الإضافية التي تنقلها في الغرض. إذا كان تطبيقك يعرض بيانات الاتصال، مثل عنوان البريد الإلكتروني أو رقم الهاتف، استخدِم
هذا الغرض للسماح للمستخدم بإضافة البيانات إلى جهة اتصال حالية.
جهة اتصال
ملاحظة: ليس من الضروري إرسال قيمة للاسم في العناصر الإضافية لهذا الغرض، لأنّ المستخدم دائمًا يختار اسمًا حاليًا أو يضيف اسمًا جديدًا. إضافةً إلى ذلك، إذا أرسلت اسمًا واختار المستخدم إجراء تعديل، سيعرض تطبيق "جهات الاتصال" الاسم الذي ترسله، وستحلّ محلّ القيمة السابقة. إذا لم يلاحظ المستخدم ذلك وحفظ التعديل، ستفقد القيمة القديمة. |
لا يسمح لك تطبيق جهات الاتصال على الجهاز بحذف جهة اتصال أولية أو أي من بياناتها بغرض. بدلاً من ذلك، يمكنك استخدام ContentResolver.delete()
أو ContentProviderOperation.newDelete()
لحذف جهة اتصال أولية.
يوضّح المقتطف التالي كيفية إنشاء وإرسال غرض يدرج جهة اتصال أو بيانات أولية جديدة:
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);
تكامل البيانات
ولأن مستودع جهات الاتصال يحتوي على بيانات مهمة وحساسة يتوقع المستخدمون أن تكون صحيحة وحديثة، فإن لدى "مقدِّم خدمة جهات الاتصال" قواعد محددة جيدًا بخصوص سلامة البيانات. وتقع على عاتقك مسؤولية الالتزام بهذه القواعد عند تعديل بيانات جهات الاتصال. في ما يلي القواعد المهمة:
-
أضِف دائمًا صف
ContactsContract.CommonDataKinds.StructuredName
لكل صفContactsContract.RawContacts
تضيفه. -
في حال توفُّر صف
ContactsContract.RawContacts
بدون صفContactsContract.CommonDataKinds.StructuredName
في الجدولContactsContract.Data
، يمكن أن يؤدي ذلك إلى حدوث مشاكل أثناء تجميع البيانات. -
يجب دائمًا ربط صفوف
ContactsContract.Data
الجديدة بالصفContactsContract.RawContacts
الرئيسي. -
لن يظهر صف
ContactsContract.Data
غير المرتبط بـContactsContract.RawContacts
في تطبيق جهات الاتصال على الجهاز، وقد يتسبب في حدوث مشاكل في محوّلات المزامنة. - غيِّر البيانات فقط لجهات الاتصال الأولية التي تملكها.
- تذكَّر أنّ مزوّد جهات الاتصال يدير عادةً البيانات من عدة أنواع مختلفة من الحسابات/الخدمات على الإنترنت. عليك التأكّد من أنّ تطبيقك يعدّل بيانات الصفوف التي تملكها فقط أو يحذفها، وأنّه لا يدرج سوى بيانات من نوع حساب واسم يمكنك التحكّم فيه.
-
استخدِم دائمًا الثوابت المحدّدة في
ContactsContract
وفئاتها الفرعية للمرجعات ومعرّفات الموارد المنتظمة (URI) للمحتوى ومسارات معرّف الموارد المنتظم (URI) وأسماء الأعمدة وأنواع MIME وقيمTYPE
. - يساعدك استخدام هذه الثوابت في تجنُّب الأخطاء. وسيتم إعلامك أيضًا بتحذيرات برامج التحويل البرمجي في حال إيقاف أي من الثوابت.
صفوف البيانات المخصّصة
من خلال إنشاء أنواع MIME مخصّصة خاصة بك واستخدامها، يمكنك إدراج صفوف بياناتك وتعديلها وحذفها واستردادها في الجدول ContactsContract.Data
. تقتصر صفوفك على استخدام العمود المحدّد في ContactsContract.DataColumns
، ولكن يمكنك ربط أسماء الأعمدة الخاصة بنوع محدّد مع أسماء الأعمدة التلقائية. في تطبيق "جهات الاتصال" على الجهاز، يتم عرض بيانات الصفوف، ولكن لا يمكن تعديلها أو حذفها، ولا يمكن للمستخدمين إضافة بيانات إضافية. للسماح للمستخدمين بتعديل صفوف البيانات المخصّصة، يجب توفير نشاط تعديل في تطبيقك الخاص.
لعرض بياناتك المخصّصة، قدِّم ملف contacts.xml
يحتوي على العنصر <ContactsAccountType>
وعنصر واحد أو أكثر من عناصر <ContactsDataKind>
الثانوية الخاصة به. يمكنك الاطّلاع على مزيد من التفاصيل في القسم <ContactsDataKind> element
.
للمزيد من المعلومات حول أنواع MIME المخصّصة، يُرجى قراءة دليل إنشاء موفِّر محتوى.
محوّلات مزامنة مزوّد جهات الاتصال
تم تصميم "مقدِّم جهات الاتصال" خصيصًا لمعالجة مزامنة بيانات جهات الاتصال بين جهاز وخدمة على الإنترنت. يتيح ذلك للمستخدمين تنزيل البيانات الحالية على جهاز جديد وتحميل البيانات الحالية إلى حساب جديد. تضمن المزامنة أيضًا توفير أحدث البيانات للمستخدمين، بغض النظر عن مصدر الإضافات والتغييرات. وهناك ميزة أخرى للمزامنة وهي أنها تجعل بيانات جهات الاتصال متاحة حتى عندما لا يكون الجهاز متصلاً بالشبكة.
على الرغم من أنّه يمكنك تنفيذ المزامنة بعدة طرق، يوفّر نظام Android إطار عمل مزامنة مكوّن إضافي يؤدي إلى تشغيل المهام التالية تلقائيًا:
- جارٍ التحقّق من توفّر الشبكة.
- جدولة عملية المزامنة وتنفيذها استنادًا إلى إعدادات المستخدم المفضَّلة.
- إعادة تشغيل المزامنات التي توقفت
لاستخدام إطار العمل هذا، يجب توفير مكوّن إضافي لمحوّل المزامنة. يكون كل محوّل مزامنة فريدًا لموفّر الخدمة والمحتوى، ولكن يمكنه التعامل مع أسماء حسابات متعددة للخدمة نفسها. ويسمح إطار العمل أيضًا باستخدام محوّلات متعددة للمزامنة مع الخدمة ومقدّم الخدمة نفسهما.
فئات وملفات محوِّل المزامنة
عليك تنفيذ محوّل مزامنة كفئة فرعية من
AbstractThreadedSyncAdapter
وتثبيتها كجزء من تطبيق Android. يتعرّف النظام على محوّل المزامنة من العناصر في بيان التطبيق،
ومن ملف XML خاص يُشار إليه في البيان. ويحدّد ملف XML
نوع حساب الخدمة على الإنترنت والهيئة الخاصة بموفِّر المحتوى، واللذين
يحدّدان معًا المحوّل بشكل فريد. لا يصبح محوّل المزامنة نشطًا حتى يضيف المستخدم
حسابًا لنوع حساب محوّل المزامنة ويمكّن المزامنة لموفّر
المحتوى الذي تتم مزامنة محوّل المزامنة معه. عندها، يبدأ النظام في إدارة المحوّل، ويطلب منه المزامنة بين موفِّر المحتوى والخادم.
ملاحظة: إنّ استخدام نوع حساب كجزء من تعريف محوّل المزامنة يتيح للنظام اكتشاف محوّلات المزامنة التي يمكنها الوصول إلى خدمات مختلفة من المؤسسة نفسها وتجميعها معًا. على سبيل المثال، تستخدم محوّلات المزامنة لخدمات Google على الإنترنت نوع الحساب com.google
نفسه. عندما يضيف المستخدمون حساب Google إلى أجهزتهم، يتم إدراج جميع محوّلات المزامنة المثبَّتة لخدمات Google معًا، وتتم مزامنة كل محوّل
مزامنة مع موفّر محتوى مختلف على الجهاز.
ولأن معظم الخدمات تتطلب من المستخدمين إثبات هويتهم قبل الوصول إلى البيانات، يوفّر نظام Android إطار عمل مصادقة يشبه إطار عمل محوّل المزامنة ويتم استخدامه غالبًا مع ذلك. يستخدم إطار عمل المصادقة
برامج مصادقة للمكوّنات الإضافية وهي فئات فرعية من
AbstractAccountAuthenticator
. يتحقّق برنامج المصادقة من هوية المستخدم باتّباع الخطوات التالية:
- جمع اسم المستخدم أو كلمة المرور أو معلومات مشابهة (بيانات اعتماد المستخدم).
- يرسل بيانات الاعتماد إلى الخدمة.
- يفحص ردّ الخدمة.
إذا قبلت الخدمة بيانات الاعتماد، يمكن لبرنامج المصادقة
تخزين بيانات الاعتماد لاستخدامها لاحقًا. وبسبب إطار عمل برنامج المصادقة، يمكن لـ AccountManager
توفير إمكانية الوصول إلى أي رموز مصادقة تتوافق مع برنامج المصادقة ويختار عرضها، مثل رموز المصادقة OAuth2.
على الرغم من أنّ المصادقة غير مطلوبة، تستخدمها معظم خدمات جهات الاتصال. ومع ذلك، لا يلزمك استخدام إطار عمل مصادقة Android لإجراء المصادقة.
تنفيذ محوّل المزامنة
لتنفيذ محوّل مزامنة لـ "مقدِّم جهات الاتصال"، عليك البدء بإنشاء تطبيق Android يحتوي على ما يلي:
-
هو مكوّن
Service
يستجيب لطلبات النظام للربط بمحوّل المزامنة. -
عندما يريد النظام تشغيل مزامنة، يستدعي طريقة
onBind()
للخدمة للحصول علىIBinder
لمحوّل المزامنة. ويسمح ذلك للنظام بإجراء طلبات متعدّدة العمليات لطرق المحوّل. -
محوِّل المزامنة الفعلي، الذي تم تنفيذه كفئة فرعية ملموسة من
AbstractThreadedSyncAdapter
. -
تؤدي هذه الفئة وظيفة تنزيل البيانات من الخادم وتحميل البيانات من
الجهاز وحلّ التعارضات. ويتم تنفيذ العمل الرئيسي للمحوّل
باستخدام الطريقة
onPerformSync()
. يجب إنشاء مثيل لهذه الفئة على أنّها فردية. -
فئة فرعية من
Application
. -
تعمل هذه الفئة كمصنِّع لمحوّل المزامنة سينغلتون. استخدِم الإجراء
onCreate()
لإنشاء مثيل لمحوّل المزامنة، ووفِّر طريقة "getter" ثابتة لإعادة التوجيه المفرد إلى طريقةonBind()
لخدمة محوِّل المزامنة. -
اختياري: مكوِّن
Service
يستجيب للطلبات الواردة من النظام لمصادقة المستخدم. -
يبدأ
AccountManager
هذه الخدمة لبدء عملية المصادقة. تُنشئ طريقةonCreate()
الخاصة بالخدمة مثيلاً لكائن برنامج المصادقة. عندما يريد النظام مصادقة حساب مستخدم لمحوّل مزامنة التطبيق، فإنّه يطلب طريقةonBind()
في الخدمة للحصول علىIBinder
لجهاز المصادقة. ويسمح هذا الإجراء للنظام بإجراء طلبات متعدّدة العمليات لأساليب برنامج المصادقة. -
اختياري: فئة فرعية ملموسة من
AbstractAccountAuthenticator
تعالج طلبات المصادقة. -
توفر هذه الفئة الطرق التي يستدعيها
AccountManager
لمصادقة بيانات اعتماد المستخدم مع الخادم. وتختلف تفاصيل عملية المصادقة بشكل كبير استنادًا إلى تقنية الخادم المستخدَمة. يجب الرجوع إلى مستندات برنامج الخادم لمعرفة المزيد من المعلومات عن المصادقة. - ملفات XML التي تحدّد محوّل المزامنة وبرنامج المصادقة للنظام.
-
يتم تحديد مكوّنات محوّل المزامنة وخدمة المصادقة الموضّحة سابقًا في عناصر
<service>
ضمن بيان التطبيق. وتحتوي هذه العناصر على<meta-data>
العناصر الثانوية التي توفّر بيانات محدّدة للنظام:-
يشير عنصر
<meta-data>
الخاص بخدمة محوّل المزامنة إلى ملف XMLres/xml/syncadapter.xml
. ويحدِّد هذا الملف بدوره معرّف الموارد المنتظم (URI) لخدمة الويب التي ستتم مزامنتها مع "مقدِّم جهات الاتصال"، ونوع حساب لخدمة الويب. -
اختياري: يشير العنصر
<meta-data>
الخاص ببرنامج المصادقة إلى ملف XMLres/xml/authenticator.xml
. ويحدد هذا الملف بدوره نوع الحساب الذي يتيحه برنامج المصادقة هذا، بالإضافة إلى موارد واجهة المستخدم التي تظهر أثناء عملية المصادقة. يجب أن يكون نوع الحساب المحدّد في هذا العنصر هو نفسه نوع الحساب المحدّد لمحوّل المزامنة.
-
يشير عنصر
بيانات مصادر البيانات الاجتماعية
يعمل الجدولان android.provider.ContactsContract.StreamItems وandroid.provider.ContactsContract.StreamItemPhotos على إدارة البيانات الواردة من الشبكات الاجتماعية. يمكنك كتابة محوّل مزامنة يضيف بيانات مصدر البيانات من شبكتك الخاصة إلى هذه الجداول، أو يمكنك قراءة بيانات مصادر البيانات من هذه الجداول وعرضها في تطبيقك الخاص، أو يمكنك استخدام كليهما. باستخدام هذه الميزات، يمكن دمج خدمات وتطبيقات الشبكات الاجتماعية في تجربة الشبكات الاجتماعية على Android.
نص ساحة مشاركات الشبكات الاجتماعية
ويتم دائمًا ربط عناصر ساحة المشاركات بجهة اتصال أولية. يرتبط android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID بالقيمة
_ID
لجهة الاتصال الأولية. ويتم أيضًا تخزين نوع الحساب واسم الحساب لجهة الاتصال الأولية في صف عنصر مصدر البيانات.
تخزين البيانات من مصدر البيانات في الأعمدة التالية:
- android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE
- مطلوب. نوع حساب المستخدم لجهة الاتصال الأولية المرتبطة بعنصر مصدر البيانات هذا. لا تنسَ ضبط هذه القيمة عند إدراج عنصر بث.
- android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME
- مطلوب. اسم حساب المستخدم لجهة الاتصال الأولية المرتبطة بعنصر مصدر البيانات هذا. لا تنسَ ضبط هذه القيمة عند إدراج عنصر بث.
- أعمدة المعرّفات
-
مطلوب. يجب إدراج أعمدة المعرّفات التالية عند
إدراج عنصر بث:
- android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID: قيمة android.provider.BaseColumns#_ID لجهة الاتصال التي يرتبط بها عنصر مصدر البيانات هذا.
- android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY: قيمة android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY في جهة الاتصال المرتبطة بعنصر ساحة المشاركات هذا.
- android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID: قيمة android.provider.BaseColumns#_ID لجهة الاتصال الأولية التي يرتبط بها عنصر مصدر البيانات هذا.
- android.provider.ContactsContract.StreamItemsColumns#COMMENTS
- اختيارية. تخزِّن معلومات الملخّص التي يمكنك عرضها في بداية عنصر البث.
- android.provider.ContactsContract.StreamItemsColumns#TEXT
-
نص عنصر البث، إمّا المحتوى الذي تم نشره من خلال مصدر العنصر،
أو وصف لإجراء ما أدى إلى إنشاء عنصر البث. ويمكن أن يحتوي هذا العمود على
أي تنسيق وصور موارد مضمَّنة يمكن عرضها بواسطة
fromHtml()
. وقد يقتطع مقدّم الخدمة المحتوى الطويل أو يقطعه، ولكنّه سيحاول تجنُّب إيقاف العلامات. - android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP
- سلسلة نصية تحتوي على الوقت الذي تم فيه إدراج عنصر البث أو تعديله، على شكل مللي ثانية منذ البداية. والتطبيقات التي تُدرج عناصر البث أو تعدّلها تكون مسؤولة عن الحفاظ على هذا العمود، ولا يتم الاحتفاظ به تلقائيًا من قِبل "مقدِّم جهات الاتصال".
لعرض معلومات تعريفية لعناصر البث، استخدِم android.provider.ContactsContract.StreamItemsColumns#RES_ICON و android.provider.ContactsContract.StreamItemsColumns#RES_LABEL و android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE للربط بالموارد في تطبيقك.
يحتوي الجدول android.provider.ContactsContract.StreamItems أيضًا على الأعمدة android.provider.ContactsContract.StreamItemsColumns#SYNC1 حتى android.provider.ContactsContract.StreamItemsColumns#SYNC4 للاستخدام الحصري لمحوّلات المزامنة.
صور المشاركات على الشبكات الاجتماعية
يخزِّن جدول android.provider.ContactsContract.StreamItemPhotos الصور المرتبطة
بعنصر بث. ويربط العمود android.provider.ContactsContract.StreamItemPhotosColumns#Stream_ITEM_ID
بالقيم في العمود "_ID
" في الجدول android.provider.ContactsContract.StreamItems. يتم تخزين مراجع الصور في
الجدول في الأعمدة التالية:
- android.provider.ContactsContract.StreamItemPhotos#PHOTO العمود (BLOB).
- تمثيل ثنائي للصورة تم تغيير حجمه من قِبل مقدّم الخدمة لأغراض التخزين والعرض. يتوفّر هذا العمود للتوافق مع الأنظمة القديمة مع الإصدارات السابقة من "موفِّر خدمة جهات الاتصال" الذي استخدمه لتخزين الصور. ومع ذلك، في الإصدار الحالي، يجب عدم استخدام هذا العمود لتخزين الصور. بدلاً من ذلك، استخدِم android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID أو android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (اللذان تم شرحهما في النقطتين التاليتَين) لتخزين الصور في ملف. يحتوي هذا العمود الآن على صورة مصغّرة للصورة المتاحة للقراءة.
- android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
-
معرّف رقمي لصورة لجهة اتصال غير معدَّلة. يمكنك إلحاق هذه القيمة بالقيمة الثابتة
DisplayPhoto.CONTENT_URI
للحصول على معرّف موارد منتظم (URI) للمحتوى يشير إلى ملف صورة واحد، ثم استدعاءopenAssetFileDescriptor()
للحصول على اسم معرِّف لملف الصورة. - android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
-
معرّف الموارد المنتظم (URI) للمحتوى الذي يشير مباشرةً إلى ملف الصورة للصورة التي يمثّلها هذا الصف.
يمكنك الاتصال بـ
openAssetFileDescriptor()
باستخدام معرّف الموارد المنتظم (URI) هذا للحصول على اسم معرِّف لملف الصورة.
استخدام جداول ساحة مشاركات الشبكات الاجتماعية
تعمل هذه الجداول بالطريقة نفسها التي تعمل بها الجداول الرئيسية الأخرى في "مزود جهات الاتصال"، باستثناء ما يلي:
- تتطلب هذه الجداول أذونات وصول إضافية. لقراءة الرسالة منها، يجب أن يحصل تطبيقك على الإذن android.Manifest.permission#READ_SOCIAL_Stream. وإذا أردت تعديلها، يجب أن يحصل التطبيق على الإذن android.Manifest.permission#WRITE_SOCIAL_Stream.
-
بالنسبة إلى جدول android.provider.ContactsContract.StreamItems، يكون عدد الصفوف
المخزَّنة لكل جهة اتصال أولية محدودًا. وعند بلوغ هذا الحدّ الأقصى، يوفّر "مقدِّم جهات الاتصال" مساحة لصفوف عناصر مصدر البيانات الجديدة من خلال حذف الصفوف التي تحتوي على الأقدم android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP تلقائيًا. للحصول على
الحدّ، يمكنك إرسال طلب بحث إلى معرّف الموارد المنتظم (URI) للمحتوى android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI. ويمكنك ترك جميع الوسيطات باستثناء معرّف الموارد المنتظم (URI) للمحتوى على
null
. يعرض طلب البحث مؤشرًا يحتوي على صف واحد يحتوي على العمود الواحد android.provider.ContactsContract.StreamItems#MAX_ITEMS.
تحدّد الفئة android.provider.ContactsContract.StreamItems.StreamItemPhotos جدولاً فرعيًا لـ android.provider.ContactsContract.StreamItemPhotos الذي يحتوي على صفوف الصور لعنصر بث واحد.
تفاعلات ساحة المشاركات على الشبكات الاجتماعية
تقدّم بيانات ساحة المشاركات على وسائل التواصل الاجتماعي التي يديرها مقدّم خدمة جهات الاتصال، مع تطبيق جهات الاتصال على الجهاز، طريقة فعّالة لربط نظام الشبكات الاجتماعية بجهات الاتصال الحالية. تتوفّر الميزات التالية:
- من خلال مزامنة خدمة الشبكة الاجتماعية مع "مقدِّم جهات الاتصال" باستخدام محوّل مزامنة، يمكنك استرداد الأنشطة الحديثة لجهات اتصال المستخدم وتخزينها في الجدولَين android.provider.ContactsContract.StreamItems وandroid.provider.ContactsContract.StreamItemPhotos للاستخدام لاحقًا.
- بالإضافة إلى المزامنة المنتظمة، يمكنك تشغيل محوّل المزامنة لاسترداد بيانات إضافية عندما يختار المستخدم جهة اتصال لعرضها. ويسمح ذلك لمحوّل المزامنة باسترداد الصور العالية الدقة وأحدث عناصر البث لجهة الاتصال.
- من خلال تسجيل إشعار في تطبيق جهات الاتصال على الجهاز و"مقدِّم خدمة جهات الاتصال"، يمكنك تلقّي هدف عند عرض جهة اتصال، وبعد ذلك تعديل حالة جهة الاتصال من خدمتك. قد تكون هذه الطريقة أسرع وتستخدم معدل نقل بيانات أقل من إجراء مزامنة كاملة باستخدام محوِّل مزامنة.
- يمكن للمستخدمين إضافة جهة اتصال إلى خدمة الشبكات الاجتماعية أثناء الاطّلاع على جهة الاتصال في تطبيق جهات الاتصال على الجهاز. يمكنك تفعيل هذه الميزة من خلال ميزة "دعوة جهة الاتصال"، التي يتم تفعيلها من خلال مجموعة من النشاط الذي يضيف جهة اتصال حالية إلى شبكتك، وملف XML الذي يوفر تطبيق جهات الاتصال على الجهاز ومزوّد جهات الاتصال مع تفاصيل تطبيقك.
المزامنة المنتظمة لعناصر البث مع "موفر جهات الاتصال" هي نفسها عمليات المزامنة الأخرى. للحصول على مزيد من المعلومات حول المزامنة، يمكنك الاطّلاع على القسم محوّلات مزامنة مزوّد جهات الاتصال. في القسمَين التاليَين، يمكنك الاطّلاع على قسمَي تسجيل الإشعارات ودعوة جهات الاتصال.
التسجيل لمعالجة طرق عرض الشبكات الاجتماعية
لتسجيل محوّل المزامنة لتلقّي الإشعارات عندما يعرض المستخدم جهة اتصال يديرها محوِّل المزامنة:
-
أنشئ ملفًا باسم
contacts.xml
في دليلres/xml/
الخاص بمشروعك. وإذا كان لديك هذا الملف حاليًا، يمكنك تخطّي هذه الخطوة. -
في هذا الملف، أضِف العنصر
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. إذا كان هذا العنصر متوفرًا من قبل، فيمكنك تخطي هذه الخطوة. -
لتسجيل خدمة يتم إشعارها عندما يفتح المستخدم صفحة تفاصيل جهة اتصال في تطبيق جهات الاتصال على الجهاز، أضِف السمة
viewContactNotifyService="serviceclass"
إلى العنصر، حيث يكونserviceclass
هو اسم فئة مؤهل بالكامل للخدمة والذي يجب أن يتلقى الغرض من تطبيق جهات الاتصال على الجهاز. بالنسبة إلى خدمة الإشعار، استخدِم فئة تمتدIntentService
، للسماح للخدمة بتلقّي رسائل intent. تحتوي بيانات الغرض الوارد على معرّف الموارد المنتظم (URI) للمحتوى لجهة الاتصال الأولية التي نقر عليها المستخدم. من خلال خدمة الإشعار، يمكنك الربط بمحوّل المزامنة ثم طلبه لتعديل بيانات جهة الاتصال الأولية.
لتسجيل نشاط ليتم الاتصال به عندما ينقر المستخدم على عنصر ساحة المشاركات أو صورة أو كليهما:
-
أنشئ ملفًا باسم
contacts.xml
في دليلres/xml/
الخاص بمشروعك. وإذا كان لديك هذا الملف حاليًا، يمكنك تخطّي هذه الخطوة. -
في هذا الملف، أضِف العنصر
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. إذا كان هذا العنصر متوفرًا من قبل، فيمكنك تخطي هذه الخطوة. -
لتسجيل أحد أنشطتك للتعامل مع نقر المستخدم على عنصر البث في
تطبيق جهات الاتصال على الجهاز، أضِف السمة
viewStreamItemActivity="activityclass"
إلى العنصر، حيثactivityclass
هو اسم الفئة المؤهّل بالكامل للنشاط الذي يجب أن يتلقى الغرض من تطبيق جهات الاتصال على الجهاز. -
لتسجيل أحد أنشطتك للتعامل مع نقر المستخدم على صورة ساحة مشاركات في تطبيق جهات الاتصال للجهاز، أضِف السمة
viewStreamItemPhotoActivity="activityclass"
إلى العنصر، حيث يكونactivityclass
هو اسم الفئة المؤهّل بالكامل للنشاط الذي يجب أن يتلقى الغرض من تطبيق جهات الاتصال على الجهاز.
يمكن الاطّلاع على مزيد من التفاصيل حول العنصر <ContactsAccountType>
في القسم عنصر<ContactsAccountType>.
يحتوي الغرض الوارد على معرّف الموارد المنتظم (URI) لمحتوى العنصر أو الصورة التي نقر عليها المستخدم. للحصول على أنشطة منفصلة للعناصر النصية والصور، استخدِم كلتا السمتَين في الملف نفسه.
التفاعل مع خدمة الشبكات الاجتماعية
ولا يتعين على المستخدمين مغادرة تطبيق جهات الاتصال على الجهاز لدعوة جهة اتصال إلى موقعك على شبكة التواصل الاجتماعي. بدلاً من ذلك، يمكنك أن تطلب من تطبيق "جهات الاتصال" على الجهاز إرسال غرض من أجل دعوة جهة الاتصال إلى أحد أنشطتك. لإعداد هذا الإجراء:
-
أنشئ ملفًا باسم
contacts.xml
في دليلres/xml/
الخاص بمشروعك. وإذا كان لديك هذا الملف حاليًا، يمكنك تخطّي هذه الخطوة. -
في هذا الملف، أضِف العنصر
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. إذا كان هذا العنصر متوفرًا من قبل، فيمكنك تخطي هذه الخطوة. -
أضِف السمات التالية:
inviteContactActivity="activityclass"
-
inviteContactActionLabel="@string/invite_action_label"
activityclass
هي اسم الفئة المؤهّل بالكامل للنشاط الذي يجب أن يحصل على الغرض. القيمةinvite_action_label
هي سلسلة نصية يتم عرضها في قائمة إضافة اتصال في تطبيق جهات الاتصال على الجهاز.
ملاحظة: ContactsSource
هو اسم علامة تم إيقافه نهائيًا للسمة ContactsAccountType
.
مرجع contacts.xml
يحتوي الملف contacts.xml
على عناصر XML التي تتحكّم في تفاعل محوِّل المزامنة والتطبيق مع تطبيق جهات الاتصال ومقدِّم خدمة جهات الاتصال. وتكون هذه العناصر موضّحة في الأقسام التالية.
عنصر <ContactsAccountType>
ويتحكم العنصر <ContactsAccountType>
في تفاعل تطبيقك مع تطبيق جهات الاتصال. وهي تحتوي على الصيغة التالية:
<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">
تحتوي على:
res/xml/contacts.xml
يمكن أن يحتوي على:
<ContactsDataKind>
الوصف:
تعريف مكونات Android وتصنيفات واجهة المستخدم التي تسمح للمستخدمين بدعوة إحدى جهات الاتصال إلى شبكة اجتماعية، وإشعار المستخدمين عند تحديث إحدى ساحات مشاركات الشبكات الاجتماعية، وما إلى ذلك.
يُرجى العِلم أنّ بادئة السمة android:
غير ضرورية لسمات <ContactsAccountType>
.
السمات:
inviteContactActivity
- اسم الفئة المؤهّل بالكامل للنشاط في تطبيقك والذي تريد تفعيله عندما يختار المستخدم إضافة اتصال من تطبيق جهات الاتصال على الجهاز.
inviteContactActionLabel
-
سلسلة نصية يتم عرضها للنشاط المحدّد في
inviteContactActivity
، في قائمة إضافة اتصال. على سبيل المثال، يمكنك استخدام السلسلة "متابعة في شبكتي". يمكنك استخدام معرِّف لمورد السلسلة لهذا التصنيف. viewContactNotifyService
- اسم فئة الخدمة المؤهّل بالكامل في تطبيقك والتي يجب أن تتلقّى إشعارات عندما يرى المستخدم جهة اتصال. يتم إرسال هذا الإشعار من خلال تطبيق جهات الاتصال في الجهاز، ويتيح للتطبيق تأجيل العمليات التي تستهلك قدرًا كبيرًا من البيانات إلى أن تكون هناك حاجة إليها. على سبيل المثال، يمكن للتطبيق الرد على هذا الإشعار من خلال قراءة صورة جهة الاتصال العالية الدقة وأحدث عناصر ساحة المشاركات على وسائل التواصل الاجتماعي وعرضها. يتم وصف هذه الميزة بمزيد من التفصيل في قسم التفاعلات مع ساحة المشاركات الاجتماعية.
viewGroupActivity
- اسم الفئة المؤهّل بالكامل لنشاط في تطبيقك والذي يمكنه عرض معلومات المجموعة. عندما ينقر المستخدم على تصنيف المجموعة في تطبيق جهات الاتصال على الجهاز، يتم عرض واجهة المستخدم لهذا النشاط.
viewGroupActionLabel
-
التصنيف الذي يعرضه تطبيق جهات الاتصال لعنصر تحكّم في واجهة المستخدم يتيح للمستخدم الاطّلاع على المجموعات في تطبيقك
معرّف مورد السلسلة مسموح به لهذه السمة.
viewStreamItemActivity
- اسم الفئة المؤهّل بالكامل لنشاط في تطبيقك الذي يشغّله تطبيق جهات الاتصال على الجهاز عندما ينقر المستخدم على عنصر بث للحصول على جهة اتصال أولية.
viewStreamItemPhotoActivity
- اسم الفئة المؤهّل بالكامل لنشاط في تطبيقك الذي يشغّله تطبيق جهات الاتصال على الجهاز عندما ينقر المستخدم على صورة في عنصر ساحة المشاركات لجهة اتصال أولية.
العنصر <ContactsDataKind>
يتحكّم العنصر <ContactsDataKind>
في عرض صفوف البيانات المخصّصة لتطبيقك في واجهة مستخدم تطبيق جهات الاتصال. وهي تحتوي على الصيغة التالية:
<ContactsDataKind android:mimeType="MIMEtype" android:icon="icon_resources" android:summaryColumn="column_name" android:detailColumn="column_name">
تحتوي على:
<ContactsAccountType>
الوصف:
استخدِم هذا العنصر ليعرض تطبيق جهات الاتصال محتوى صف بيانات مخصّص كجزء من تفاصيل جهة اتصال أولية. يمثل كل عنصر <ContactsDataKind>
ثانوي من <ContactsAccountType>
نوعًا من صف البيانات المخصّصة الذي يضيفه محوِّل المزامنة إلى جدول ContactsContract.Data
. أضِف عنصر <ContactsDataKind>
واحدًا لكل نوع MIME مخصّص تستخدمه. وليس عليك
إضافة العنصر إذا كان لديك صف بيانات مخصّص لا تريد عرض بياناته.
السمات:
android:mimeType
-
نوع MIME المخصّص الذي حدّدته لأحد أنواع صفوف البيانات المخصّصة في جدول
ContactsContract.Data
. على سبيل المثال، يمكن أن تكون القيمةvnd.android.cursor.item/vnd.example.locationstatus
نوع MIME مخصّصًا لصف بيانات يسجّل آخر موقع جغرافي معروف لجهة اتصال. android:icon
- مورد قابل للرسم على جهاز Android يعرضه تطبيق جهات الاتصال بجانب بياناتك. يمكنك استخدام هذه السمة لإعلام المستخدم بأنّ البيانات واردة من خدمتك.
android:summaryColumn
- اسم العمود لأول قيمتين يتم استرداده من صف البيانات. يتم عرض القيمة على أنّها السطر الأول من الإدخال لصف البيانات هذا. يهدف السطر الأول إلى استخدامه كملخص للبيانات، إلا أنّ هذا الإجراء اختياري. راجِع أيضًا android:detailColumn.
android:detailColumn
-
اسم العمود للقيم الثانية من قيمتين يتم استردادهما من صف البيانات. يتم عرض القيمة على أنّها السطر الثاني من إدخال صف البيانات هذا. يمكنك أيضًا الاطّلاع على
android:summaryColumn
.
الميزات الإضافية لمقدّم خدمة جهات الاتصال
بالإضافة إلى الميزات الرئيسية الموضّحة في الأقسام السابقة، يوفّر "مقدِّم جهات الاتصال" هذه الميزات المفيدة للتعامل مع بيانات جهات الاتصال:
- مجموعات جهات الاتصال
- ميزات الصور
مجموعات جهات الاتصال
يمكن لمقدّم جهات الاتصال تصنيف مجموعات من جهات الاتصال ذات الصلة باستخدام بيانات المجموعة بشكل اختياري. إذا كان الخادم المرتبط بحساب مستخدم
يريد الاحتفاظ بالمجموعات، يجب أن ينقل محوّل المزامنة لنوع حساب الحساب
بيانات المجموعات بين "مقدِّم جهات الاتصال" والخادم. وعندما يضيف المستخدمون جهة اتصال جديدة إلى
الخادم ثم يضعون جهة الاتصال هذه في مجموعة جديدة، يجب أن يضيف محوِّل المزامنة المجموعة الجديدة
إلى جدول ContactsContract.Groups
. ويتم تخزين المجموعة أو المجموعات التي تنتمي إليها جهة اتصال أولية في جدول ContactsContract.Data
باستخدام النوع MIME ContactsContract.CommonDataKinds.GroupMembership
.
إذا كنت تصمم محوّل مزامنة سيضيف بيانات جهات اتصال أولية من
الخادم إلى "مقدِّم جهات الاتصال"، ولا تستخدم المجموعات، يجب إبلاغ
موفّر الخدمة بجعل بياناتك مرئية. في الرمز الذي يتم تنفيذه عندما يضيف مستخدم حسابًا إلى الجهاز، عدِّل الصف ContactsContract.Settings
الذي يضيفه مزوّد جهات الاتصال للحساب. في هذا الصف، اضبط قيمة عمود
Settings.UNGROUPED_VISIBLE
على 1. عند إجراء ذلك، سيجعل "مقدِّم جهات الاتصال" دائمًا
بيانات جهات اتصالك مرئية، حتى إذا لم تكن تستخدم مجموعات.
صور جهات الاتصال
يخزِّن الجدول ContactsContract.Data
الصور كصفوف من النوع MIME
Photo.CONTENT_ITEM_TYPE
. يرتبط عمود CONTACT_ID
للصف بالعمود _ID
لجهة الاتصال الأولية التي تنتمي إليها.
تحدّد الفئة ContactsContract.Contacts.Photo
جدولاً فرعيًا لـ ContactsContract.Contacts
يحتوي على معلومات الصورة للصورة الأساسية لجهة الاتصال، وهي الصورة الأساسية لجهة الاتصال الأولية الأولية لجهة الاتصال. وبالمثل، تحدّد الفئة ContactsContract.RawContacts.DisplayPhoto
جدولاً فرعيًا لـ ContactsContract.RawContacts
يحتوي على معلومات الصورة للصورة الأساسية لجهة الاتصال الأولية.
تتضمن المستندات المرجعية الخاصة بالسمتَين ContactsContract.Contacts.Photo
وContactsContract.RawContacts.DisplayPhoto
أمثلة على استرداد معلومات الصورة. ما مِن فئة مناسبة لاسترداد الصورة المصغّرة الأساسية لجهة اتصال أولية، ولكن يمكنك إرسال طلب بحث إلى جدول ContactsContract.Data
مع اختيار عمودَي _ID
وPhoto.CONTENT_ITEM_TYPE
وIS_PRIMARY
لجهة الاتصال الأولية للعثور على صف الصورة الأساسية لجهة الاتصال الأولية.
وقد تتضمن بيانات ساحة المشاركات على وسائل التواصل الاجتماعي للمستخدم صورًا أيضًا. ويتم تخزينها في جدول android.provider.ContactsContract.StreamItemPhotos الموضح بمزيد من التفصيل في قسم صور ساحة المشاركات على الشبكات الاجتماعية.