مقدِّم جهات الاتصال هو مكوّن Android فعّال ومرن يدير مستودع البيانات المركزي على الجهاز والمتعلّق بالأشخاص. "مقدِّم جهات الاتصال" هو مصدر البيانات التي تظهر في تطبيق إدارة جهات الاتصال على الجهاز، ويمكنك أيضًا الوصول إلى بياناته في تطبيقك ونقل البيانات بين الجهاز والخدمات على الإنترنت. يستوعب مقدّم الخدمة مجموعة كبيرة من مصادر البيانات ويحاول إدارة أكبر قدر ممكن من البيانات لكل شخص، ما يؤدي إلى تعقيد عملية تنظيم البيانات. لهذا السبب، تتضمّن واجهة برمجة التطبيقات الخاصة بموفّر المحتوى مجموعة شاملة من الصفوف المرافقة والواجهات التي تسهّل استرداد البيانات وتعديلها.
يصف هذا الدليل ما يلي:
- البنية الأساسية لمقدّم الخدمة
- كيفية استرداد البيانات من مقدّم الخدمة
- كيفية تعديل البيانات في مقدّم الخدمة
- كيفية كتابة محوّل مزامنة لمزامنة البيانات من الخادم إلى مقدِّم جهات الاتصال
يفترض هذا الدليل أنّك على دراية بأساسيات أدوات توفير المحتوى في Android. لمزيد من المعلومات حول أدوات توفير المحتوى في Android، يُرجى الاطّلاع على دليل أساسيات أدوات توفير المحتوى.
مؤسسة مقدِّم جهات الاتصال
"مقدِّم جهات الاتصال" هو أحد مكوّنات أداة توفير المحتوى في Android. ويحتفظ بثلاثة أنواع من البيانات عن الشخص، يتوافق كل منها مع جدول يوفّره مقدّم الخدمة، كما هو موضّح في الشكل 1:
الشكل 1: بنية جدول "مقدِّم جهات الاتصال"
يُشار عادةً إلى الجداول الثلاثة بأسماء صفوفها المرافقة. تحدّد الفئات ثوابت لمعرّفات الموارد المنتظمة للمحتوى وأسماء الأعمدة وقيم الأعمدة التي تستخدمها الجداول:
-
جدول
ContactsContract.Contacts - صفوف تمثّل أشخاصًا مختلفين، استنادًا إلى تجميعات صفوف جهات الاتصال الأوليّة.
-
جدول
ContactsContract.RawContacts - صفوف تحتوي على ملخّص لبيانات شخص معيّن، وتكون خاصة بحساب مستخدم ونوعه.
-
جدول
ContactsContract.Data - الصفوف التي تحتوي على تفاصيل جهة الاتصال الأوليّة، مثل عناوين البريد الإلكتروني أو أرقام الهواتف
والجداول الأخرى التي تمثّلها الصفوف المرافقة في ContactsContract
هي جداول مساعدة يستخدمها "مقدِّم جهات الاتصال" لإدارة عملياته أو إتاحة
وظائف معيّنة في جهات الاتصال أو تطبيقات الاتصال الهاتفي على الجهاز.
جهات الاتصال الأولية
تمثّل جهة الاتصال الأوليّة بيانات مستخدم واردة من نوع حساب واحد واسم حساب واحد. بما أنّ "مقدِّم جهات الاتصال" يسمح بأكثر من خدمة واحدة على الإنترنت كمصدر لبيانات الشخص، فإنّه يسمح بجهات اتصال أوليّة متعددة للشخص نفسه. تتيح جهات الاتصال الأوليّة المتعدّدة أيضًا للمستخدم دمج بيانات شخص من أكثر من حساب من نوع الحساب نفسه.
لا يتم تخزين معظم بيانات جهة الاتصال الأوليّة في الجدول
ContactsContract.RawContacts. بدلاً من ذلك، يتم تخزينها في صف واحد أو أكثر في جدول ContactsContract.Data. يحتوي كل صف بيانات على عمود
Data.RAW_CONTACT_ID يتضمّن قيمة RawContacts._ID
لصف ContactsContract.RawContacts الرئيسي.
أعمدة جهات الاتصال الأولية المهمة
الأعمدة المهمة في جدول ContactsContract.RawContacts
مُدرَجة في الجدول 1. يُرجى قراءة الملاحظات التي تلي الجدول:
الجدول 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.comemilyd@gmail.com- حساب Twitter "belle_of_amherst"
فعّل هذا المستخدم ميزة مزامنة جهات الاتصال لجميع هذه الحسابات الثلاثة في إعدادات الحسابات.
لنفترض أنّ "إميلي ديكنسون" تفتح نافذة متصفّح وتسجّل الدخول إلى Gmail باسم
emily.dickinson@gmail.com، ثم تفتح
"جهات الاتصال" وتضيف "توماس هيغينسون". في وقت لاحق، تسجّل الدخول إلى Gmail باستخدام الحساب
emilyd@gmail.com وترسل رسالة إلكترونية إلى "Thomas Higginson"، ما يؤدي تلقائيًا إلى
إضافته كجهة اتصال. وتتابع أيضًا "colonel_tom" (رقم تعريف توماس هيغينسون على 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يضع علامة على صف البيانات الذي يحتوي على البيانات الأساسية للنوع. على سبيل المثال، إذا ضغط المستخدم مع الاستمرار على رقم هاتف لجهة اتصال واختار التحديد كخيار تلقائي، سيتم ضبط العمودIS_PRIMARYفي الصفContactsContract.Dataالذي يحتوي على هذا الرقم على قيمة غير صفرية.
أسماء الأعمدة العامة
هناك 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، وكيفية "تراكب" أسماء الأعمدة الخاصة بالنوع مع أسماء الأعمدة العامة
الشكل 2: أسماء الأعمدة الخاصة بالنوع وأسماء الأعمدة العامة
فئات أسماء الأعمدة الخاصة بالنوع
يسرد الجدول 2 فئات أسماء الأعمدة الأكثر استخدامًا والخاصة بالنوع:
الجدول 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.Contacts أيضًا على العمود
LOOKUP_KEY الذي يمثّل رابطًا
"دائمًا" لصف جهة الاتصال. بما أنّ "مقدِّم جهات الاتصال" يحتفظ بجهات الاتصال تلقائيًا، قد يغيّر قيمة _ID لصف جهة اتصال استجابةً لعملية تجميع أو مزامنة. حتى في حال حدوث ذلك، سيظل معرّف الموارد المنتظم للمحتوى
CONTENT_LOOKUP_URI مع
LOOKUP_KEY لجهة الاتصال
يشير إلى صف جهة الاتصال، لذا يمكنك استخدام
LOOKUP_KEY
للاحتفاظ بالروابط المؤدية إلى جهات الاتصال "المفضّلة"، وما إلى ذلك. يحتوي هذا العمود على تنسيق خاص به لا يرتبط بتنسيق العمود _ID.
يوضّح الشكل 3 كيفية ارتباط الجداول الثلاثة الرئيسية ببعضها.
الشكل 3: العلاقات بين جداول "جهات الاتصال" و"جهات الاتصال الأوليّة" و"التفاصيل"
تنبيه: إذا نشرت تطبيقك على "متجر Google Play" أو إذا كان تطبيقك مثبّتًا على جهاز يعمل بنظام التشغيل Android 10 (المستوى 29 من واجهة برمجة التطبيقات) أو إصدار أحدث، يُرجى العِلم بأنّ مجموعة محدودة من حقول بيانات جهات الاتصال وطرقها أصبحت قديمة.
Under the conditions mentioned, the system periodically clears any values written to these data fields:
-
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 كيفية ملاءمة "مقدِّم جهات الاتصال" لتدفق البيانات حول الأشخاص. في المربّع الذي يحمل اسم "محوّلات المزامنة"، يتم تصنيف كل محوّل حسب نوع الحساب.
الشكل 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(). اضبط معرّف الموارد المنتظم للمحتوى على
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 واحد. ولتسهيل ذلك، يوفّر مقدِّم جهات الاتصال بُنى الكيانات التي تعمل مثل عمليات دمج قواعد البيانات بين الجداول.
الكيان يشبه جدولاً يتألف من أعمدة محدّدة من جدول رئيسي وجدول فرعي.
عند الاستعلام عن كيان، يمكنك تقديم إسقاط ومعايير بحث استنادًا إلى الأعمدة
المتاحة من الكيان. والنتيجة هي 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 هذا لعرضها أو العمل عليها بشكل أكبر.
التعديل المجمّع
Whenever possible, you should insert, update, and delete data in the Contacts Provider in
"batch mode", by creating an ArrayList of
ContentProviderOperation objects and calling
applyBatch(). بما أنّ "مقدِّم جهات الاتصال" ينفّذ جميع العمليات في applyBatch() في معاملة واحدة، لن تترك تعديلاتك مستودع جهات الاتصال في حالة غير متّسقة. يُسهّل التعديل المجمّع أيضًا إدراج جهة اتصال أولية وبياناتها التفصيلية في الوقت نفسه.
ملاحظة: لتعديل جهة اتصال أوليّة واحدة، ننصحك بإرسال intent إلى تطبيق لإدارة جهات الاتصال على الجهاز بدلاً من معالجة التعديل في تطبيقك. يتم شرح ذلك بمزيد من التفصيل في قسم الاسترداد والتعديل باستخدام النيات.
نقاط الخضوع
يمكن أن يؤدي التعديل المجمّع الذي يحتوي على عدد كبير من العمليات إلى حظر عمليات أخرى،
ما يؤدي إلى تجربة مستخدم سيئة بشكل عام. لتنظيم جميع التعديلات التي تريد
إجراءها في أقل عدد ممكن من القوائم المنفصلة، وفي الوقت نفسه منعها من
حظر النظام، يجب ضبط نقاط الخضوع لعملية واحدة أو أكثر.
نقطة الخضوع هي عنصر 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، وإذا حاولت إجراء إشارة مرجعية إلى نتيجة لعملية لم يتم تطبيقها بعد، سيتم عرضExceptionمن خلالwithValueBackReference().
توضّح المقتطفات التالية كيفية إدراج جهة اتصال أوليّة وبيانات جديدة في دفعة واحدة. وتتضمّن هذه الأمثلة رمزًا يحدّد نقطة خضوع ويستخدم مرجعًا خلفيًا.
يسترد المقتطف الأول بيانات جهات الاتصال من واجهة المستخدم. في هذه المرحلة، يكون المستخدم قد اختار الحساب الذي يجب إضافة جهة الاتصال الأولية الجديدة إليه.
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). بالنسبة إلى معرّف الموارد المنتظم للمحتوى، استخدِم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 إلى تطبيق لإدارة جهات الاتصال على الجهاز الوصول إلى مقدِّم جهات الاتصال بشكل غير مباشر. يبدأ الغرض واجهة مستخدم تطبيق لإدارة جهات الاتصال على الجهاز، حيث يمكن للمستخدمين تنفيذ المهام المتعلقة بجهات الاتصال. باستخدام هذا النوع من الوصول، يمكن للمستخدمين إجراء ما يلي:
- اختَر جهة اتصال من قائمة وأعِدها إلى تطبيقك لمزيد من العمل.
- تعديل بيانات جهة اتصال حالية
- إدراج جهة اتصال أوليّة جديدة لأي من حساباتهم
- حذف جهة اتصال أو بيانات جهات الاتصال
إذا كان المستخدم يُدخل بيانات أو يعدّلها، يمكنك جمع البيانات أولاً وإرسالها كجزء من الطلب.
عند استخدام الأهداف للوصول إلى مقدِّم جهات الاتصال من خلال تطبيق إدارة جهات الاتصال على الجهاز، لن تحتاج إلى كتابة واجهة مستخدم أو رمز برمجي خاص بك للوصول إلى المقدِّم. ولا تحتاج أيضًا إلى طلب الإذن بالقراءة أو الكتابة إلى الموفّر. يمكن لتطبيق إدارة جهات الاتصال على الجهاز تفويض إذن القراءة لجهة اتصال معيّنة إليك، وبما أنّك تُجري تعديلات على المزوّد من خلال تطبيق آخر، ليس عليك الحصول على أذونات التعديل.
يتم شرح العملية العامة لإرسال طلب intent للوصول إلى أداة توفير المحتوى بالتفصيل في دليل
أساسيات أداة توفير المحتوى ضمن قسم "الوصول إلى البيانات من خلال طلبات intent". يتم تلخيص الإجراء ونوع MIME وقيم البيانات التي تستخدمها للمهام المتاحة في الجدول 4، بينما يتم إدراج قيم الإضافات التي يمكنك استخدامها مع putExtra() في المستندات المرجعية لـ ContactsContract.Intents.Insert:
الجدول 4: أهداف مقدِّم جهات الاتصال
| المهمة | الإجراء | البيانات | نوع 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
|
يعرض هذا الغرض دائمًا شاشة أداة الاختيار في تطبيق جهات الاتصال. يمكن للمستخدم اختيار جهة اتصال لتعديلها أو إضافة جهة اتصال جديدة. تظهر شاشة التعديل أو الإضافة، حسب اختيار المستخدم، ويتم عرض البيانات الإضافية التي تم تمريرها في الطلب. إذا كان تطبيقك يعرض بيانات جهة اتصال، مثل عنوان بريد إلكتروني أو رقم هاتف، يمكنك استخدام
هذا الغرض للسماح للمستخدم بإضافة البيانات إلى جهة اتصال حالية.
جهة اتصال،
ملاحظة: ليس من الضروري إرسال قيمة اسم في الإضافات الخاصة بهذا الغرض، لأنّ المستخدم يختار دائمًا اسمًا حاليًا أو يضيف اسمًا جديدًا. علاوةً على ذلك، إذا أرسلت اسمًا واختار المستخدم إجراء تعديل، سيعرض تطبيق جهات الاتصال الاسم الذي أرسلته، وسيتم استبدال القيمة السابقة. إذا لم يلاحظ المستخدم ذلك وحفظ التعديل، ستُفقد القيمة القديمة. |
لا يسمح لك تطبيق جهات الاتصال على الجهاز بحذف جهة اتصال أولية أو أي من بياناتها باستخدام
intent. بدلاً من ذلك، لحذف جهة اتصال أولية، استخدِم
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وفئاتها الفرعية للسلطات ومعرّفات الموارد المنتظمة للمحتوى ومسارات معرّفات الموارد المنتظمة وأسماء الأعمدة وأنواع 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. -
تعمل هذه الفئة كمصنع لنمط singleton لمحوّل المزامنة. استخدِم طريقة
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للحصول على معرّف موارد منتظم للمحتوى يشير إلى ملف صورة واحدة، ثم استدعِ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 لاستخدامه لاحقًا.
- بالإضافة إلى المزامنة العادية، يمكنك تفعيل محوّل المزامنة لاسترداد بيانات إضافية عندما يختار المستخدم جهة اتصال لعرضها. يتيح ذلك لمحوّل المزامنة استرداد الصور العالية الدقة وأحدث عناصر البث لجهة الاتصال.
- من خلال تسجيل إشعار في تطبيق لإدارة جهات الاتصال على الجهاز ومقدِّم جهات الاتصال، يمكنك تلقّي intent عند عرض جهة اتصال، وفي هذه المرحلة يمكنك تعديل حالة جهة الاتصال من خدمتك. قد يكون هذا الأسلوب أسرع ويستخدم معدل نقل بيانات أقل من إجراء مزامنة كاملة باستخدام محوّل مزامنة.
- يمكن للمستخدمين إضافة جهة اتصال إلى خدمة الشبكات الاجتماعية أثناء الاطّلاع على جهة الاتصال في تطبيق إدارة جهات الاتصال على الجهاز. يمكنك تفعيل هذه الميزة من خلال ميزة "دعوة جهة اتصال"، التي يمكنك تفعيلها من خلال مجموعة من الأنشطة التي تضيف جهة اتصال حالية إلى شبكتك، وملف XML الذي يوفّر تطبيق لإدارة جهات الاتصال على الجهاز و "مقدِّم جهات الاتصال" مع تفاصيل تطبيقك.
تتشابه المزامنة المنتظمة لعناصر البث مع "مقدِّم جهات الاتصال" مع عمليات المزامنة الأخرى. لمزيد من المعلومات حول المزامنة، يُرجى الاطّلاع على قسم محوّلات مزامنة مقدِّم جهات الاتصال. يتم تناول تسجيل الإشعارات ودعوة جهات الاتصال في القسمَين التاليَين.
التسجيل للتعامل مع مشاهدات الشبكات الاجتماعية
لتسجيل محوّل المزامنة لتلقّي إشعارات عندما يعرض المستخدم جهة اتصال يديرها محوّل المزامنة:
-
أنشِئ ملفًا باسم
contacts.xmlفي دليلres/xml/الخاص بمشروعك. إذا كان لديك هذا الملف، يمكنك تخطّي هذه الخطوة. -
في هذا الملف، أضِف العنصر
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">. إذا كان هذا العنصر موجودًا من قبل، يمكنك تخطّي هذه الخطوة. -
لتسجيل خدمة يتم إشعارها عندما يفتح المستخدم صفحة تفاصيل جهة اتصال في
تطبيق لإدارة جهات الاتصال على الجهاز، أضِف السمة
viewContactNotifyService="serviceclass"إلى العنصر، حيثserviceclassهو اسم الفئة المؤهَّل بالكامل للخدمة التي من المفترض أن تتلقّى الغرض من تطبيق لإدارة جهات الاتصال على الجهاز. بالنسبة إلى خدمة الإشعارات، استخدِم فئة تمدّدIntentServiceللسماح للخدمة بتلقّي الأهداف. تحتوي البيانات في الطلب الوارد على معرّف الموارد المنتظم للمحتوى لجهة الاتصال الأولية التي نقر عليها المستخدم. من خدمة الإشعارات، يمكنك الربط بمحوّل المزامنة ثم استدعاؤه لتعديل بيانات جهة الاتصال الأوليّة.
لتسجيل نشاط يتم استدعاؤه عندما ينقر المستخدم على عنصر في الخلاصة أو صورة أو كليهما:
-
أنشِئ ملفًا باسم
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، باستخدام نوع 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، الموضَّح بمزيد من التفصيل في قسم صور ساحة المشاركات الاجتماعية.