موفِّر جهات الاتصال هو مكوّن قوي ومرن في Android يدير مستودع الجهاز المركزي للبيانات عن الأشخاص. موفِّر جهات الاتصال هو مصدر البيانات التي تظهر في تطبيق جهات الاتصال على الجهاز، ويمكنك أيضًا الوصول إلى بياناته في تطبيقك الخاص ونقل البيانات بين الجهاز والخدمات على الإنترنت. يتعامل مقدّم الخدمة مع مجموعة كبيرة من مصادر البيانات ويحاول إدارة أكبر قدر ممكن من البيانات لكل شخص، مما يؤدي بدوره إلى كون تنظيمه معقدًا. ولهذا السبب، تتضمّن واجهة برمجة التطبيقات الخاصة بالموفّر مجموعة واسعة من فئات العقود وواجهاتها التي تسهّل استرداد البيانات وتعديلها.
يوضّح هذا الدليل ما يلي:
- بنية مقدّم الخدمة الأساسية
- كيفية استرداد البيانات من مقدّم الخدمة
- كيفية تعديل البيانات في الموفِّر.
- كيفية كتابة محوِّل مزامنة لمزامنة البيانات من خادمك إلى موفِّر جهات الاتصال
يفترض هذا الدليل أنّك على دراية بأساسيات موفّري محتوى Android. لمعرفة مزيد من المعلومات حول موفّري محتوى Android، يُرجى الاطّلاع على دليل أساسيات موفّر المحتوى.
مؤسسة مقدّم جهات الاتصال
"موفِّر جهات الاتصال" هو مكوّن لموفِّر محتوى Android. ويحتفظ هذا السجلّ بثلاثة أنواع من البيانات عن الشخص، يرتبط كلّ منها بجدول يوفّره مقدّم الخدمة، كما هو موضح في الشكل 1:
ويُشار إلى الجداول الثلاثة عادةً بأسماء فئات العقود. تحدّد الفئات ثوابتًا لمعرّفات الموارد المنتظمة (URI) الخاصة بالمحتوى وأسماء الأعمدة وقيم الأعمدة التي تستخدمها الجداول:
-
جدول
ContactsContract.Contacts
- الصفوف التي تمثّل أشخاصًا مختلفين استنادًا إلى تجميعات صفوف جهات الاتصال الأوّلية
-
جدول
ContactsContract.RawContacts
- الصفوف التي تحتوي على ملخّص لبيانات شخص معيّن، خاصة بحساب مستخدم ونوعه
-
جدول
ContactsContract.Data
- الصفوف التي تحتوي على تفاصيل جهة الاتصال الأوّلية، مثل عناوين البريد الإلكتروني أو أرقام الهواتف
الجداول الأخرى التي تمثلها فئات العقود في ContactsContract
هي جداول إضافية يستخدمها "موفّر جهات الاتصال" لإدارة عملياته أو لإتاحة وظائف
معيّنة في جهات الاتصال على الجهاز أو تطبيقات الاتصال الهاتفي.
جهات الاتصال الأولية
تمثّل جهة الاتصال الأوّلية بيانات شخص تأتي من نوع حساب واحد واسم حساب واحد. بما أنّ مقدّم جهات الاتصال يسمح بأكثر من خدمة واحدة على الإنترنت كمصدر لبيانات المستخدم، يسمح مقدّم جهات الاتصال بعدة جهات اتصال أولية للمستخدم نفسه. تسمح جهات الاتصال الأوّلية المتعددة للمستخدم أيضًا بدمج بيانات شخص من أكثر من حساب واحد من نوع الحساب نفسه.
لا يتم تخزين معظم بيانات جهة الاتصال الأوّلية في جدول
ContactsContract.RawContacts
. بدلاً من ذلك، يتم تخزينها في صف واحد أو أكثر
في جدول ContactsContract.Data
. يتضمّن كل صف بيانات عمودًا
Data.RAW_CONTACT_ID
يحتوي على القيمة RawContacts._ID
في
صفه الرئيسي ContactsContract.RawContacts
.
أعمدة جهات الاتصال الأوّلية المهمة
يتم إدراج الأعمدة المهمة في جدول ContactsContract.RawContacts
في الجدول 1. يُرجى قراءة الملاحظات التالية بعد الجدول:
اسم العمود | استخدام | ملاحظات |
---|---|---|
ACCOUNT_NAME
|
اسم الحساب لنوع الحساب الذي يمثل مصدر جهة الاتصال الأولية هذه.
على سبيل المثال، اسم حساب Google هو أحد عناوين Gmail
الخاصة بمالك الجهاز. راجِع الإدخال التالي لرمز
ACCOUNT_TYPE للحصول على مزيد من
المعلومات.
|
يرتبط تنسيق هذا الاسم بنوع الحساب. ولا يلزم أن يكون عنوان بريد إلكتروني. |
ACCOUNT_TYPE
|
نوع الحساب الذي هو مصدر جهة الاتصال الأولية هذه. على سبيل المثال، نوع حساب حساب Google هو com.google . يجب دائمًا تأهيل نوع حسابك
باستخدام معرّف نطاق لنطاق تملكه أو تتحكّم فيه. سيضمن ذلك أنّ نوع حسابك
سيكون فريدًا.
|
يكون عادةً محوّل مزامنة مرتبط بنوع الحساب الذي يوفّر بيانات جهات الاتصال يتزامن مع "مقدِّم جهات الاتصال". |
DELETED
|
علامة "تم حذفها" لجهة اتصال غير معالجة | تسمح هذه العلامة لموفِّر جهات الاتصال بالاحتفاظ بالصفّ داخليًا إلى أن يتمكّن محوِّلو المزامنة من حذف الصفّ من خوادمهم ثم حذفه نهائيًا من المستودع. |
ملاحظات
في ما يلي ملاحظات مهمة حول جدول
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@gmail.com
emilyd@gmail.com
- حساب Twitter "belle_of_amherst"
فعَّل هذا المستخدم ميزة مزامنة جهات الاتصال لجميع هذه الحسابات الثلاثة في إعدادات الحسابات.
لنفترض أنّ "إميلي ديكنسون" فتحت نافذة متصفّح وسجّلت الدخول إلى Gmail باسم
emily.dickinson@gmail.com
، ثم فتحت
"جهات الاتصال" وأضافت "توماس هيغينزون". في وقت لاحق، سجّلت مها الدخول إلى Gmail باستخدام حساب
emilyd@gmail.com
وأرسلت رسالة إلكترونية إلى "توماس هيغينز"، ما أدّى إلى
إضافته تلقائيًا كجهة اتصال. وهي تتابع أيضًا "colonel_tom" (رقم تعريف "توماس هيغينسون" على Twitter) على
Twitter.
ينشئ مقدّم جهات الاتصال ثلاث جهات اتصال أولية نتيجةً لهذا العمل:
-
جهة اتصال أولية لـ "توماس هيغينزون" مرتبطة بـ
emily.dickinson@gmail.com
نوع حساب المستخدم هو Google. -
جهة اتصال ثانية غير معالجة لـ "توماس هيغينزون" مرتبطة بـ
emilyd@gmail.com
. ونوع حساب المستخدم هو أيضًا Google. هناك جهة اتصال أساسية ثانية حتى إذا كان الاسم مطابقًا لاسم سابق، لأنّه تمت إضافة الشخص لحساب مستخدم مختلف. - جهة اتصال ثالثة غير معالجة لـ "توماس هيغينزون" مرتبطة بـ "belle_of_amherst" ويكون نوع حساب المستخدم على Twitter.
البيانات
كما ذكرنا سابقًا، يتم تخزين بيانات جهة الاتصال الأوّلية في صف
ContactsContract.Data
مرتبط بقيمة
_ID
لجهة الاتصال الأوّلية. ويتيح ذلك لجهة اتصال أولية واحدة الاحتفاظ بمثيلات متعددة من النوع نفسه من البيانات، مثل عناوين البريد الإلكتروني أو أرقام الهواتف. على سبيل المثال، إذا كان "توماس هيغينزون" emilyd@gmail.com
(صف جهة الاتصال الأوّلي لـ "توماس هيغينزون" المرتبط بحساب 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
صف البيانات الذي يحتوي على البيانات الأساسية للنوع. على سبيل المثال، إذا الضغط مع الاستمرار على رقم هاتف لأحد جهات الاتصال واختيار ضبط القيمة التلقائية، سيتم ضبط عمودIS_PRIMARY
في الصفContactsContract.Data
الذي يحتوي على الرقم على قيمة غير صفرية.
أسماء الأعمدة العامة
هناك 15 عمودًا عامًا يتضمّن الاسم من DATA1
إلى
DATA15
وتتوفر بشكل عام وأربعة أعمدة إضافية
عامة من SYNC1
إلى SYNC4
يجب استخدامها فقط في محوّلات المزامنة. تعمل ثوابت أسماء الأعمدة العامة دائمًا، بغض النظر عن نوع
البيانات التي يحتوي عليها الصف.
تم فهرسة عمود DATA1
. يستخدم موفِّر جهات الاتصال هذا العمود دائمًا لتحديد
البيانات التي يتوقع الموفِّر أن تكون الهدف الأكثر تكرارًا لطلب البحث. على سبيل المثال،
في صف الرسالة الإلكترونية، يحتوي هذا العمود على عنوان البريد الإلكتروني الفعلي.
وفقًا للعرف، يتم حجز العمود DATA15
لتخزين بيانات Binary Large Object
(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
، وكيفية "تداخل" أسماء الأعمدة الخاصة بالأنواع
مع أسماء الأعمدة العامة.
فئات أسماء الأعمدة الخاصة بالنوع
يسرد الجدول 2 فئات أسماء الأعمدة الأكثر استخدامًا حسب النوع:
فئة الربط | نوع البيانات | ملاحظات |
---|---|---|
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.RawContacts
المرتبط بكل صف من صفوف ContactsContract.RawContacts
الأوّلية.
يحتوي جدول ContactsContract.Contacts
أيضًا على العمود
LOOKUP_KEY
الذي يمثّل
رابطًا "دائمًا" بصف جهة الاتصال. بما أنّ موفِّر جهات الاتصال يحتفظ بجهات الاتصال
تلقائيًا، قد يغيّر قيمة _ID
في صف جهة الاتصال
استجابةً لعملية تجميع أو مزامنة. حتى في حال حدوث ذلك، سيظلّ عنوان URL للمحتوى
CONTENT_LOOKUP_URI
مع
LOOKUP_KEY
جهة الاتصال يشير
إلى صف جهة الاتصال، لذا يمكنك استخدام
LOOKUP_KEY
للاحتفاظ بالروابط التي تؤدي إلى جهات الاتصال "المفضّلة" وما إلى ذلك. يحتوي هذا العمود على تنسيق خاص به
لا علاقة له بتنسيق عمود _ID
.
يوضّح الشكل 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
(لا يؤثّر إلا في أنواع البيانات البريد الإلكتروني والهاتف وقابل للاتصال فقط)
إذا كانت تطبيقاتك تحصل على هذه الحقول أو واجهات برمجة التطبيقات أو تعدّلها، استخدِم methodsبديلة. على سبيل المثال، يمكنك استيفاء بعض حالات الاستخدام من خلال الاستعانة بموفّري المحتوى الخاص أو البيانات الأخرى المخزّنة في تطبيقك أو أنظمتنا الخلفية.
للتأكّد من أنّ وظيفة تطبيقك لم تتأثّر بهذا التغيير، يمكنك محو حقول البيانات هذه يدويًا. لتنفيذ ذلك، شغِّل الأمر التالي لـ ADB على جهاز يعمل بالإصدار 4.1 من نظام التشغيل Android (المستوى 16 من واجهة برمجة التطبيقات) أو إصدار أحدث:
adb shell content delete \ --uri content://com.android.contacts/contacts/delete_usage
بيانات من محوّلات المزامنة
يُدخل المستخدمون بيانات جهات الاتصال مباشرةً في الجهاز، ولكن يتم أيضًا نقل البيانات إلى موفِّر جهات الاتصال من خدمات الويب من خلال محوِّلات المزامنة التي تُبرمج نقل البيانات بين الجهاز والخدمات. تعمل محوّلات المزامنة في الخلفية
تحت تحكّم النظام، وتطلب طرق ContentResolver
لإدارة البيانات.
في Android، يتم تحديد خدمة الويب التي يعمل معها محوِّل المزامنة حسب نوع الحساب. يعمل كل محوِّل مزامنة مع نوع حساب واحد، ولكن يمكن أن يتيح أسماء حسابات متعددة لهذا النوع. يتم وصف أنواع الحسابات وأسماء الحسابات بشكل مختصر في القسم مصادر بيانات جهات الاتصال الأوّلية. تقدّم التعريفات التالية المزيد من التفاصيل، وتوضّح كيفية ارتباط نوع الحساب واسمه بمحوِّلات المزامنة وخدماتها.
- نوع الحساب
-
تحدّد هذه السمة خدمة خزّن المستخدم البيانات فيها. وفي أغلب الأحيان، يتعين على المستخدم
المصادقة مع الخدمة. على سبيل المثال، جهات اتصال Google هي نوع حساب يتم تعريفه
بالرمز
google.com
. تتوافق هذه القيمة مع نوع الحساب المستخدَم من قِبلAccountManager
. - اسم الحساب
- يحدِّد حسابًا معيّنًا أو تسجيل دخول لنوع حساب معيّن. حسابات "جهات اتصال Google" هي نفسها حسابات Google التي تستخدم عنوان بريد إلكتروني كاسم حساب. قد تستخدم الخدمات الأخرى اسم مستخدم مكوّنًا من كلمة واحدة أو معرّفًا رقميًا.
ولا يُشترط أن تكون أنواع الحسابات فريدة. يمكن للمستخدم ضبط حسابات متعدّدة على "جهات اتصال Google" وتنزيل بياناتها إلى مقدّم جهات الاتصال. وقد يحدث ذلك إذا كان لدى المستخدم مجموعة واحدة من جهات الاتصال الشخصية لاسم حساب شخصي ومجموعة أخرى للعمل. تكون أسماء الحسابات عادةً فريدة. ويعملان معًا على تحديد تدفق بيانات محدّد بين موفِّر جهات الاتصال و خدمة خارجية.
إذا كنت تريد نقل بيانات خدمتك إلى مقدّم جهات الاتصال، عليك كتابة محوِّل المزامنة الخاص بك. ويتم وصف ذلك بمزيد من التفصيل في القسم محوِّلات مزامنة موفّري جهات الاتصال.
يوضّح الشكل 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 الوصول إلى data التي تُحدِّد هوية مستخدم الجهاز. احرص على إطلاع المستخدم على سبب حاجتك لأذونات الوصول إلى الملف الشخصي للمستخدم في وصف التطبيق.
لاسترداد صف جهة الاتصال الذي يحتوي على الملف الشخصي للمستخدم،
اتصل بالرقم 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
. يوضّح الجدول التالي تأثير كل جزء من هذه البيانات الوصفية:
جدول | العمود | القيم | المعنى |
---|---|---|---|
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 |
(all) | استخدِم هذا الجدول لتخزين البيانات الوصفية لمحوِّل المزامنة. | باستخدام هذا الجدول، يمكنك تخزين حالة المزامنة والبيانات الأخرى ذات الصلة بالمزامنة باستمرار على جهازك. |
إذن الوصول إلى مقدّم جهات الاتصال
يصف هذا القسم إرشادات الوصول إلى البيانات من "مزوّد جهات الاتصال"، مع التركيز على ما يلي:
- طلبات البحث عن الكيانات.
- تعديل مجمّع
- الاسترجاع والتعديل بأغراض.
- سلامة البيانات:
ويمكنك أيضًا الاطّلاع على مزيد من التفاصيل بشأن إجراء التعديلات من محوّل المزامنة في القسم محوّلات مزامنة موفّر جهات الاتصال.
طلب البحث عن الكيانات
بما أنّ جداول مقدّم جهات الاتصال منظَّمة بشكل هرمي، غالبًا ما يكون من المفيد
استرداد صف وجميع الصفوف "الفرعية" المرتبطة به. على سبيل المثال، لعرض
كل المعلومات الخاصة بشخص معيّن، قد تحتاج إلى استرداد كل صفوف
ContactsContract.RawContacts
لصف واحد
ContactsContract.Contacts
، أو كل صفوف
ContactsContract.CommonDataKinds.Email
لصف واحد
ContactsContract.RawContacts
. لتسهيل ذلك، يقدّم موفِّر ملف جهات الاتصال بنى الكيانات التي تعمل مثل عمليات دمج قاعدة البيانات بين الجداول.
الكيان يشبه جدولاً مكونًا من أعمدة محددة من جدول رئيسي وجدوله الفرعي.
عند طلب معلومات عن عنصر، عليك تقديم عرض ومعايير بحث استنادًا إلى الأعمدة
المتاحة من العنصر. والنتيجة هي 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 }
الاسترجاع والتعديل بأغراض
يتيح لك إرسال نية إلى تطبيق جهات الاتصال على الجهاز الوصول إلى موفِّر جهات الاتصال بشكل غير مباشر. يبدأ الغرض من فتح واجهة المستخدم لتطبيق جهات الاتصال على الجهاز، والتي يمكن للمستخدمين من خلالها تنفيذ الأعمال المتعلقة بجهات الاتصال. باستخدام هذا النوع من أذونات الوصول، يمكن للمستخدمين إجراء ما يلي:
- اختر جهة اتصال من قائمة واطلب منها إعادتها إلى تطبيقك لمزيد من العمل.
- تعديل بيانات جهة اتصال حالية
- إدراج بيانات جهة اتصال جديدة في تنسيقها الأصلي لأي من حساباته
- حذف بيانات جهة اتصال أو جهات اتصال
إذا كان المستخدم يُدخِل بيانات أو يعدّلها، يمكنك جمع البيانات أولاً وإرسالها كجزء من الطلب.
وعند استخدام عناصر intent للوصول إلى "مقدِّم خدمات جهات الاتصال" من خلال تطبيق جهات الاتصال على الجهاز، لن تحتاج إلى كتابة واجهة المستخدم الخاصة بك أو رمز خاص بك للوصول إلى المزوِّد. ولن تحتاج أيضًا إلى طلب إذن بالقراءة أو الكتابة إلى الموفّر. يمكن لتطبيق جهات الاتصال على الجهاز تفويض إذن القراءة لجهة اتصال إليك، وبما أنّك تُجري تعديلات على موفِّر الخدمات من خلال تطبيق آخر، ليس عليك الحصول على أذونات الكتابة.
يمكنك الاطّلاع على العملية العامة لإرسال طلب الوصول إلى مقدّم خدمة بالتفصيل في دليل
أساسيات مقدّمي المحتوى ضمن قسم "الوصول إلى البيانات من خلال الطلبات". في الجدول 4، تم تلخيص الإجراء و
نوع MIME وقيم البيانات التي تستخدمها للمهام المتاحة، في حين تم إدراج
قيم الإضافات التي يمكنك استخدامها مع
putExtra()
في مستندات مرجعية
ContactsContract.Intents.Insert
:
المهمة | الإجراء | البيانات | نوع MIME | ملاحظات |
---|---|---|---|---|
اختيار جهة اتصال من قائمة | ACTION_PICK |
أحد الخيارَين التاليَين:
|
لم يتم الاستخدام |
تعرِض هذه السمة قائمة بجهات الاتصال الأوّلية أو قائمة بالبيانات من جهة اتصال أوّلية، استنادًا إلى نوع
معرف الموارد المنتظم للمحتوى الذي تقدّمه.
استدعاء دالة
|
إدراج جهة اتصال جديدة غير معالجة | Insert.ACTION |
لا ينطبق |
RawContacts.CONTENT_TYPE ، نوع MIME لمجموعة من جهات الاتصال الأولية.
|
يعرض شاشة إضافة جهة اتصال في تطبيق جهات الاتصال على الجهاز. يتم عرض
قيم الإضافات التي تضيفها إلى الطلب. في حال الإرسال باستخدام
startActivityForResult() ،
يتمّ تمرير معرّف الموارد المنتظم للمحتوى الخاص بجهة الاتصال الأوّلية التي تمت إضافتها حديثًا إلى onActivityResult()
طريقة الاستدعاء في نشاطك ضمن الوسيطة Intent في الحقل
"data". للحصول على القيمة، اتّصِل بالرقم 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
و الفئات الفرعية لها للسلطات وعناوين URL للمحتوى ومسارات عناوين URL وأسماء الأعمدة وأنواع 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()
لإنشاء مثيل لمحوِّر المزامنة، و قدِّم طريقة "جلب" ثابتة لعرض العنصر الفردي على الأسلوبonBind()
لخدمة محوِّر المزامنة. -
اختياري: مكوّن
Service
يستجيب للطلبات الواردة من النظام لمصادقة المستخدم -
يبدأ
AccountManager
هذه الخدمة لبدء عملية مصادقة. تنشئ طريقةonCreate()
في الخدمة مثيلًا لعنصر المصادقة. عندما يريد النظام مصادقة حساب مستخدم لمحوّل مزامنة التطبيق، يستدعي طريقةonBind()
للخدمة للحصول علىIBinder
لبرنامج المصادقة. يتيح ذلك للنظام إجراء طلبات متعدّدة المعالجة لأساليب برنامج المصادقة. -
اختياري: فئة فرعية محدّدة من
AbstractAccountAuthenticator
تعالج طلبات المصادقة. -
توفّر هذه الفئة طرقًا يستدعيها
AccountManager
لمصادقة بيانات اعتماد المستخدم مع الخادم. تختلف تفاصيل عملية المصادقة على نطاق واسع، استنادًا إلى تكنولوجيا الخادم المستخدَمة. يجب مراجعة مستندات برنامج الخادم للاطّلاع على مزيد من المعلومات عن المصادقة. - ملفات XML التي تحدد محول المزامنة والمصادق للنظام.
-
تم تحديد مكونات خدمة محوِّل المزامنة وخدمات المصادقة الموضّحة سابقًا
في عناصر
<service>
في بيان التطبيق. تحتوي هذه العناصر على<meta-data>
عناصر فرعية تقدّم بيانات محدّدة للنظام:-
يشير عنصر
<meta-data>
لخدمة محوِّل المزامنة إلىملف XMLres/xml/syncadapter.xml
. ويحدِّد هذا الملف بدوره عنوان URL لخدمة الويب التي ستتم مزامنتها مع مقدّم جهات الاتصال، ونوع حساب لخدمة الويب. -
اختياري: يشير عنصر
<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.ContactsContacts.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.Contacts استخدم.StreamItemscolumn#COMMENTS
- اختيارية. تخزِّن معلومات موجزة يمكنك عرضها في بداية عنصر مصدر بيانات.
- android.provider.ContactsContract.StreamItemsColumns#TEXT
-
نص عنصر البث، سواء كان المحتوى الذي نشره مصدر العنصر،
أو وصفًا لبعض الإجراءات التي أدّت إلى إنشاء عنصر البث يمكن أن يحتوي هذا العمود على
أي تنسيق وصور موارد مضمّنة يمكن عرضها باستخدام
fromHtml()
. قد يقطع موفّر المحتوى المحتوى الطويل أو يحذف منه أجزاء، ولكن سيحاول تجنُّب تقسيم العلامات. - android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP
- سلسلة نصية تحتوي على وقت إدراج عنصر البث أو تعديله، على شكل ملي ثانية منذ بدء حساب الوقت وتكون التطبيقات التي تدرج عناصر ساحة المشاركات أو تعدِّلها مسؤولة عن الحفاظ على هذا العمود، ولا تتم إدارته تلقائيًا من خلال "موفّر جهات الاتصال".
لعرض معلومات تعريفية لعناصر البث، استخدِم #RES_ICON في android.provider.ContactsContract.StreamItemsColumns و#RES_LABEL في android.provider.ContactsContract.StreamItemsColumns و#RES_PACKAGE في android.provider.ContactsContract.StreamItemsColumns للربط بالموارد في تطبيقك.
يحتوي جدول 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. يتم تخزين مراجع الصور في جدول
في الأعمدة التالية:
- عمود PHOTO في android.provider.ContactsContract.StreamItemPhotos# (وهو ملف BLOB)
- عرض ثنائي للصورة، يغيّر مقدّم الخدمة حجمه لتخزينه وعرضه يتوفّر هذا العمود للتوافق مع الإصدارات السابقة من موفِّر جهات الاتصال الذي كان يستخدمه لتخزين الصور. ومع ذلك، في الإصدار الحالي، يجب عدم استخدام هذا العمود لتخزين الصور. وبدلاً من ذلك، استخدِم android.provider.Contacts استخدم.StreamItemPhotosColumns#PHOTO_FILE_ID أو android.provider.ContactsFilters.StreamItemPhotosColumns#PHOTO_URI (المستندان الموضّحان في النقاط التالية) إلى تخزين الصور في أيّ ملف. يحتوي هذا العمود الآن على صورة مصغّرة للصورة المتاحة للقراءة.
- android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
-
هو معرّف رقمي لصورة جهة اتصال أوّلية. أضِف هذه القيمة إلى الثابت
DisplayPhoto.CONTENT_URI
للحصول على معرّف موارد منتظم للمحتوى يشير إلى ملف صورة واحد، ثم استخدِمopenAssetFileDescriptor()
للحصول على معرّف ملف الصورة. - android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
-
معرّف موارد منتظم للمحتوى يشير مباشرةً إلى ملف الصورة التي يمثّلها هذا الصف
اتصل بـ
openAssetFileDescriptor()
باستخدام معرّف URI هذا للحصول على معرّف ملف الصورة.
استخدام جداول "البثّ على الشبكات الاجتماعية"
تعمل هذه الجداول بالطريقة نفسها التي تعمل بها الجداول الرئيسية الأخرى في "موفر جهات الاتصال"، باستثناء ما يلي:
- تتطلّب هذه الجداول أذونات وصول إضافية. للقراءة من هذه المصادر، يجب أن يحصل تطبيقك على الإذن android.Manifest.permission#READ_SOCIAL_STREAM. لتعديلها، يجب أن يحصل تطبيقك على الإذن android.Manifest.permission#WRITE_SOCIAL_STREAM.
-
بالنسبة إلى جدول android.provider.ContactsContract.StreamItems، يكون عدد الصفوف
المخزّنة لكل جهة اتصال أولية محدودًا. بعد بلوغ هذا الحد،
يُفسح مقدّم جهات الاتصال مساحة لصفوف عناصر البث الجديدة عن طريق حذف
الصفوف التي تحتوي على أقدم قيمة لـ
android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP. للحصول على
الحدّ الأقصى، أدخِل طلب بحث إلى معرّف الموارد المنتظم للمحتوى
android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_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 لاستخدامها لاحقًا.
- بالإضافة إلى المزامنة العادية، يمكنك تفعيل محوِّل المزامنة لاسترداد بيانات إضافية عندما يختار المستخدم جهة اتصال لعرضها. يتيح ذلك لمحوِّل المزامنة retrieving استرداد الصور العالية الدقة وأحدث عناصر البث لجهة الاتصال.
- من خلال تسجيل إشعار في تطبيق جهات الاتصال على الجهاز وموفِّر جهات الاتصال، يمكنك تلقّي نية عند عرض جهة اتصال، وعند هذه النقطة، يمكنك تعديل حالة جهة الاتصال من خدمتك. قد يكون هذا الأسلوب أسرع ويستخدم معدل نقل بيانات أقل مقارنةً بإجراء مزامنة كاملة باستخدام محوِّل مزامنة.
- يمكن للمستخدمين إضافة جهة اتصال إلى خدمة الشبكات الاجتماعية أثناء الاطّلاع على جهة الاتصال في تطبيق جهات الاتصال على الجهاز. يمكنك تفعيل هذه الميزة باستخدام ميزة "دعوة جهة اتصال"، والتي يمكنك تفعيلها من خلال نشاط يضيف جهة اتصال حالية إلى الشبكة وملف XML يقدّم لتطبيق جهات الاتصال على الجهاز ومقدّم "جهات الاتصال" تفاصيل تطبيقك.
إنّ مزامنة عناصر البث العادية مع مقدّم خدمة جهات الاتصال هي مماثلة للمزامنات الأخرى. لمزيد من المعلومات عن المزامنة، اطّلِع على القسم محوِّلات مزامنة موفِّر جهات الاتصال. يتناول القسمان التاليان محتوى تسجيل الإشعارات ودعوة جهات الاتصال.
التسجيل للتعامل مع مشاهدات الشبكات الاجتماعية
لتسجيل محوِّر المزامنة لتلقّي إشعارات عندما يطّلع المستخدم على جهة اتصال تديرها أداة محوِّر المزامنة:
-
أنشئ ملفًا باسم
contacts.xml
في الدليلres/xml/
في مشروعك. إذا كان لديك هذا الملف، يمكنك تخطّي هذه الخطوة. -
في هذا الملف، أضِف العنصر
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. إذا كان هذا العنصر متوفّرًا، يمكنك تخطّي هذه الخطوة. -
لتسجيل خدمة يتم إعلامها عندما يفتح المستخدم صفحة تفاصيل جهة اتصال في
تطبيق جهات اتصال الجهاز، أضِف السمة
viewContactNotifyService="serviceclass"
إلى العنصر، حيثserviceclass
هي فئة اسم مؤهَّل بالكامل للخدمة التي من المفترض أن تتلقّى النية من تطبيق جهات اتصال الجهاز. وبالنسبة إلى خدمة مُرسِل الإشعارات، يمكنك استخدام فئة تمتد إلىIntentService
للسماح للخدمة بتلقي الأهداف. تحتوي البيانات في النية الواردة على معرّف الموارد المنتظم (URI) للمحتوى الذي نقر عليه المستخدم. من خدمة المُرسِل، يمكنك الربط ثمّ الاتصال بمحوِّل المزامنة لتعديل بيانات جهة الاتصال الأوّلية.
لتسجيل نشاط ليتمّ استدعاؤه عندما ينقر المستخدم على عنصر بث أو صورة أو كليهما:
-
أنشئ ملفًا باسم
contacts.xml
في الدليلres/xml/
في مشروعك. إذا كان لديك هذا الملف من قبل، يمكنك تخطّي هذه الخطوة. -
في هذا الملف، أضِف العنصر
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. إذا كان هذا العنصر متوفّرًا، يمكنك تخطّي هذه الخطوة. -
لتسجيل أحد الأنشطة من أجل معالجة النقر على عنصر بث في
تطبيق جهات اتصال الجهاز، أضِف السمة
viewStreamItemActivity="activityclass"
إلى العنصر، حيث يكونactivityclass
هو اسم فئة النشاط المؤهَّل بالكامل الذي من المفترض أن يتلقّى النية من تطبيق جهات اتصال الجهاز. -
لتسجيل أحد الأنشطة من أجل معالجة النقر على صورة بث في
تطبيق جهات اتصال الجهاز، أضِف السمة
viewStreamItemPhotoActivity="activityclass"
إلى العنصر، حيث يكونactivityclass
هو اسم فئة النشاط المؤهَّل بالكامل الذي من المفترض أن يتلقّى النية من تطبيق جهات اتصال الجهاز.
يمكنك الاطّلاع على وصف أكثر تفصيلاً للعنصر <ContactsAccountType>
في
قسم عنصر<ContactsAccountType>.
يحتوي الإجراء الوارد على معرّف الموارد الموحّد للمحتوى الخاص بالعنصر أو الصورة التي نقر عليها المستخدم. للحصول على أنشطة منفصلة للعناصر النصية والصور، استخدِم السمتَين في الملف نفسه.
التفاعل مع خدمة الشبكات الاجتماعية
لا يحتاج المستخدمون إلى مغادرة تطبيق جهات الاتصال على الجهاز لدعوة جهة اتصال إلى موقعك الإلكتروني على الشبكة الاجتماعية. بدلاً من ذلك، يمكنك أن تطلب من تطبيق جهات اتصال الجهاز إرسال نية لدعوة جهة الاتصال إلى أحد الأنشطة. لإعداد هذه الميزة:
-
أنشئ ملفًا باسم
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
، باستخدام نوع ContactsContract.CommonDataKinds.GroupMembership
MIME.
إذا كنت بصدد تصميم محوِّل مزامنة سيضيف بيانات جهات الاتصال الأوّلية من
الخادم إلى مقدّم جهات الاتصال، ولا تستخدم المجموعات، عليك إخبار
مقدّم الخدمة بجعل بياناتك مرئية. في الرمز البرمجي الذي يتم تنفيذه عندما يضيف مستخدم حسابًا
إلى الجهاز، عدِّل صف 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، والذي تم وصفه بالتفصيل في القسم صور خلاصة الشبكات الاجتماعية.