Contacts Provider هو أحد مكونات 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.com
emilyd@gmail.com
- حساب Twitter "belle_of_amherst"
فعّل هذا المستخدم خيار مزامنة جهات الاتصال لجميع هذه الحسابات الثلاثة في إعدادات الحسابات.
لنفترض أنّ إميلي ديكنسون تفتح نافذة متصفّح، وتسجّل الدخول إلى Gmail بصفتها
emily.dickinson@gmail.com
، وتفتح
جهات الاتصال، وتضيف "توماس هيغنسون". في وقت لاحق، تسجّل الدخول إلى Gmail باسم
emilyd@gmail.com
وترسل رسالة إلكترونية إلى "توماس هيغينسون"، ما يؤدي إلى إضافته تلقائيًا كجهة اتصال. وهي تتابع أيضًا الحساب "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
الخاصة بجهة الاتصال الأولية. يتيح ذلك أن يتضمّن جهة اتصال أولية واحدة عدة مثيلات من النوع نفسه من البيانات، مثل عناوين البريد الإلكتروني أو أرقام الهواتف. على سبيل المثال، إذا كان
"توماس هيغينسون" في 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) مثل الصور المصغّرة.
أسماء الأعمدة الخاصة بنوع معيّن
لتسهيل العمل مع الأعمدة لنوع معيّن من الصفوف، يوفّر Contacts Provider أيضًا ثوابت لأسماء الأعمدة خاصة بالنوع، ويتم تحديدها في الفئات الفرعية من 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
لصف جهة اتصال استجابةً لعملية تجميع أو مزامنة. وحتى في حال حدوث ذلك، سيظل معرّف الموارد المنتظم (URI) الخاص بالمحتوى CONTENT_LOOKUP_URI
مدمجًا مع LOOKUP_KEY
الخاص بجهة الاتصال، ما يتيح لك استخدام LOOKUP_KEY
للحفاظ على الروابط المؤدية إلى جهات الاتصال "المفضّلة" وما إلى ذلك. يحتوي هذا العمود على تنسيق خاص به لا صلة له بتنسيق العمود _ID
.
يوضّح الشكل 3 كيفية ارتباط الجداول الرئيسية الثلاثة ببعضها البعض.

الشكل 3. علاقات جداول جهات الاتصال وجهات الاتصال الأولية والتفاصيل
تنبيه: إذا نشرت تطبيقك على "متجر Google Play"، أو إذا كان تطبيقك يعمل على جهاز Android 10 (المستوى 29 لواجهة برمجة التطبيقات) أو إصدار أحدث، يُرجى العِلم أنّ مجموعة محدودة من حقول البيانات وطُرقها الخاصة بجهات الاتصال أصبحت قديمة.
في ظل الشروط المذكورة، يمحو النظام بشكل دوري أي قيم تمت كتابتها في حقول البيانات التالية:
-
ContactsContract.ContactOptionsColumns.LAST_TIME_CONTACTED
-
ContactsContract.ContactOptionsColumns.TIMES_CONTACTED
-
ContactsContract.DataUsageStatColumns.LAST_TIME_USED
-
ContactsContract.DataUsageStatColumns.TIMES_USED
أصبحت واجهات برمجة التطبيقات المستخدَمة لضبط حقول البيانات أعلاه قديمة أيضًا:
بالإضافة إلى ذلك، لم تعُد الحقول التالية تعرض جهات الاتصال المتكررة. يُرجى العِلم أنّ بعض هذه الحقول تؤثّر في ترتيب جهات الاتصال فقط عندما تكون جهات الاتصال جزءًا من نوع بيانات معيّن.
-
ContactsContract.Contacts.CONTENT_FREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_URI
-
ContactsContract.Contacts.CONTENT_STREQUENT_FILTER_URI
-
CONTENT_FILTER_URI
(يؤثر فقط في أنواع البيانات البريد الإلكتروني والهاتف والجهات التي يمكن الاتصال بها وجهات الاتصال) -
ENTERPRISE_CONTENT_FILTER_URI
(يؤثر فقط في أنواع البيانات البريد الإلكتروني والهاتف والبيانات القابلة للاتصال)
إذا كانت تطبيقاتك تصل إلى هذه الحقول أو واجهات برمجة التطبيقات أو تعدّلها، استخدِم طرقًا بديلة. على سبيل المثال، يمكنك تنفيذ بعض حالات الاستخدام من خلال استخدام موفّري المحتوى الخاص أو البيانات الأخرى المخزَّنة داخل تطبيقك أو أنظمة الخلفية.
للتأكّد من أنّ وظائف تطبيقك لن تتأثّر بهذا التغيير، يمكنك محو حقول البيانات هذه يدويًا. لإجراء ذلك، نفِّذ أمر ADB التالي على جهاز يعمل بالإصدار 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 كيف يتناسب "مزوّد جهات الاتصال" مع تدفق البيانات حول المستخدمين. في المربّع الذي يحمل العلامة "مزامنة المحوّلات"، يتم تصنيف كل محوّل حسب نوع الحساب.

الشكل 4 مسار بيانات "مقدّم جهات الاتصال"
الأذونات المطلوبة
يجب أن تطلب التطبيقات التي تريد الوصول إلى "موفّر جهات الاتصال" الأذونات التالية:
- إذن القراءة في جدول واحد أو أكثر
-
READ_CONTACTS
، المحدّد فيAndroidManifest.xml
باستخدام العنصر<uses-permission>
كـ<uses-permission android:name="android.permission.READ_CONTACTS">
- إذن الكتابة في جدول واحد أو أكثر
-
WRITE_CONTACTS
، المحدّد فيAndroidManifest.xml
باستخدام العنصر<uses-permission>
كـ<uses-permission android:name="android.permission.WRITE_CONTACTS">
لا تنطبق هذه الأذونات على بيانات الملف الشخصي للمستخدم. يتم تناول ملف المستخدم الشخصي والأذونات المطلوبة في القسم التالي، ملف المستخدم الشخصي.
يُرجى العِلم أنّ بيانات جهات اتصال المستخدم هي بيانات شخصية وحسّاسة. يشعر المستخدمون بالقلق بشأن خصوصيتهم، لذا لا يريدون أن تجمع التطبيقات بيانات عنهم أو عن جهات الاتصال الخاصة بهم. إذا لم يكن سبب حاجتك إلى إذن الوصول إلى بيانات جهات الاتصال واضحًا، قد يمنح المستخدمون تطبيقك تقييمات منخفضة أو يرفضون تثبيته.
الملف الشخصي للمستخدم
يحتوي جدول ContactsContract.Contacts
على صف واحد يتضمّن بيانات الملف الشخصي لمستخدم الجهاز. تصف هذه البيانات user
الجهاز بدلاً من إحدى جهات اتصال المستخدم. يرتبط صف جهات اتصال الملف الشخصي بصف جهات اتصال أولية لكل نظام يستخدم ملفًا شخصيًا.
يمكن أن يحتوي كل صف من صفوف جهات الاتصال الأولية في الملف الشخصي على صفوف بيانات متعددة. تتوفّر الثوابت اللازمة للوصول إلى الملف الشخصي للمستخدم في الفئة ContactsContract.Profile
.
يتطلّب الوصول إلى ملف المستخدم الشخصي أذونات خاصة. بالإضافة إلى إذنَي
READ_CONTACTS
وWRITE_CONTACTS
اللازمَين للقراءة والكتابة، يتطلّب الوصول إلى الملف الشخصي للمستخدم الإذنَين android.Manifest.permission#READ_PROFILE وandroid.Manifest.permission#WRITE_PROFILE للوصول للقراءة والكتابة، على التوالي.
تذكَّر أنّ ملف المستخدم الشخصي يُعدّ معلومات حساسة. يسمح لك الإذن android.Manifest.permission#READ_PROFILE بالوصول إلى بيانات التعريف الشخصية لمستخدم الجهاز. احرص على إخبار المستخدمين في وصف تطبيقك عن سبب حاجتك إلى أذونات الوصول إلى الملف الشخصي للمستخدم.
لاسترداد صف جهة الاتصال الذي يحتوي على الملف الشخصي للمستخدم،
اتّصِل بالدالة ContentResolver.query()
. اضبط معرّف الموارد المنتظم (URI) الخاص بالمحتوى على
CONTENT_URI
ولا تقدّم أي معايير اختيار. يمكنك أيضًا استخدام معرّف الموارد المنتظمة (URI) الخاص بالمحتوى هذا كمعرّف موارد منتظمة (URI) أساسي لاسترداد جهات الاتصال الأولية أو البيانات الخاصة بالملف الشخصي. على سبيل المثال، يستردّ مقتطف الرمز هذا البيانات الخاصة بالملف الشخصي:
Kotlin
// Sets the columns to retrieve for the user profile projection = arrayOf( ContactsContract.Profile._ID, ContactsContract.Profile.DISPLAY_NAME_PRIMARY, ContactsContract.Profile.LOOKUP_KEY, ContactsContract.Profile.PHOTO_THUMBNAIL_URI ) // Retrieves the profile from the Contacts Provider profileCursor = contentResolver.query( ContactsContract.Profile.CONTENT_URI, projection, null, null, null )
Java
// Sets the columns to retrieve for the user profile projection = new String[] { Profile._ID, Profile.DISPLAY_NAME_PRIMARY, Profile.LOOKUP_KEY, Profile.PHOTO_THUMBNAIL_URI }; // Retrieves the profile from the Contacts Provider profileCursor = getContentResolver().query( Profile.CONTENT_URI, projection , null, null, null);
ملاحظة: إذا استرجعت عدة صفوف لجهات الاتصال، وأردت تحديد ما إذا كان أحدها يمثّل الملف الشخصي للمستخدم، اختبِر العمود IS_USER_PROFILE
في الصف. يتم ضبط قيمة هذا العمود على "1" إذا كانت جهة الاتصال هي الملف الشخصي للمستخدم.
البيانات الوصفية لمقدّم جهات الاتصال
يدير "مقدّم جهات الاتصال" البيانات التي تتتبّع حالة بيانات جهات الاتصال في المستودع. يتم تخزين هذه البيانات الوصفية الخاصة بالمستودع في أماكن مختلفة، بما في ذلك صفوف جداول Raw Contacts وData وContacts، وجدول 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
. ولتسهيل ذلك، يوفّر Contacts
Provider بنى الكيانات التي تعمل مثل عمليات الربط بين الجداول في قاعدة البيانات.
الكيان هو جدول يتألف من أعمدة محددة من جدول رئيسي وجدول فرعي.
عند طلب معلومات عن كيان، عليك تقديم عرض ومعايير بحث استنادًا إلى الأعمدة المتاحة من الكيان. والنتيجة هي 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
هذا لعرضها أو استخدامها بشكل أكبر.
التعديل المجمّع
يجب إدراج البيانات وتعديلها وحذفها في Contacts Provider في "وضع الدُفعات" كلما أمكن ذلك، وذلك من خلال إنشاء ArrayList
من عناصر ContentProviderOperation
واستدعاء applyBatch()
. بما أنّ Contacts Provider ينفّذ جميع العمليات في 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
الجديدة. نتيجةً لذلك، يتم تلقائيًا ربط كل صف بيانات بصف ContactsContract.RawContacts
الجديد الذي ينتمي إليه من خلال RAW_CONTACT_ID
.
يتم وضع علامة 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". يتم تلخيص الإجراء ونوع MIME وقيم البيانات التي تستخدمها للمهام المتاحة في الجدول 4، بينما يتم إدراج قيم الإضافات التي يمكنك استخدامها مع putExtra()
في المستندات المرجعية الخاصة بـ ContactsContract.Intents.Insert
:
الجدول 4. أهداف مقدّم جهات الاتصال
المهمة | الإجراء | البيانات | نوع MIME | الملاحظات |
---|---|---|---|---|
اختيار جهة اتصال من قائمة | ACTION_PICK |
أحد الخيارات التالية:
|
لم يتم الاستخدام |
تعرض هذه السمة قائمة بجهات الاتصال الأولية أو قائمة بالبيانات من جهة اتصال أولية، وذلك حسب نوع معرّف الموارد المنتظم (URI) للمحتوى الذي تقدّمه.
Call
|
إدراج جهة اتصال أولية جديدة | 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
وفئاتها الفرعية للسلطات وعناوين URI الخاصة بالمحتوى ومسارات URI وأسماء الأعمدة وأنواع MIME وقيمTYPE
. - يساعدك استخدام هذه الثوابت في تجنُّب الأخطاء. سيتم أيضًا إرسال إشعار إليك يتضمّن تحذيرات من المحول البرمجي إذا تم إيقاف أي من الثوابت نهائيًا.
صفوف البيانات المخصّصة
من خلال إنشاء أنواع MIME مخصّصة واستخدامها، يمكنك إدراج صفوف البيانات الخاصة بك وتعديلها وحذفها واستردادها في جدول ContactsContract.Data
. تقتصر الصفوف على استخدام العمود المحدّد في ContactsContract.DataColumns
، ولكن يمكنك ربط أسماء الأعمدة الخاصة بنوع معيّن بأسماء الأعمدة التلقائية. في تطبيق جهات الاتصال على الجهاز، يتم عرض بيانات الصفوف ولكن لا يمكن تعديلها أو حذفها، ولا يمكن للمستخدمين إضافة بيانات إضافية. للسماح للمستخدمين بتعديل صفوف البيانات المخصّصة، يجب توفير نشاط محرر في تطبيقك.
لعرض بياناتك المخصّصة، يجب توفير ملف contacts.xml
يحتوي على العنصر <ContactsAccountType>
وعنصر ثانوي واحد أو أكثر من العناصر الثانوية <ContactsDataKind>
. يتم توضيح ذلك بمزيد من التفصيل في القسم <ContactsDataKind> element
.
لمزيد من المعلومات حول أنواع MIME المخصّصة، يُرجى الاطّلاع على دليل إنشاء موفّر محتوى.
محوّلات مزامنة "مقدّم جهات الاتصال"
تم تصميم "مزوّد جهات الاتصال" خصيصًا للتعامل مع مزامنة بيانات جهات الاتصال بين الجهاز وإحدى الخدمات على الإنترنت. ويتيح ذلك للمستخدمين تنزيل البيانات الحالية على جهاز جديد وتحميل البيانات الحالية إلى حساب جديد. تضمن المزامنة أيضًا حصول المستخدمين على أحدث البيانات، بغض النظر عن مصدر الإضافات والتغييرات. من المزايا الأخرى للمزامنة أنّها تتيح بيانات جهات الاتصال حتى عندما لا يكون الجهاز متصلاً بالشبكة.
على الرغم من إمكانية تنفيذ المزامنة بطرق متنوعة، يوفّر نظام Android إطار عمل للمزامنة يمكن توصيله وتنفيذه، وهو يتيح تنفيذ المهام التالية آليًا:
- جارٍ التحقّق من توفّر الشبكة.
- جدولة المزامنة وتنفيذها استنادًا إلى الإعدادات المفضّلة للمستخدم
- إعادة تشغيل عمليات المزامنة التي توقّفت
لاستخدام هذا الإطار، عليك توفير مكوّن إضافي لمحوّل المزامنة. كل محوّل مزامنة فريد بالنسبة إلى خدمة وموفّر محتوى، ولكن يمكنه التعامل مع أسماء حسابات متعددة للخدمة نفسها. يتيح إطار العمل أيضًا استخدام العديد من محوّلات المزامنة للخدمة والموفّر نفسيهما.
فئات وملفات محوّل المزامنة
يمكنك تنفيذ أداة مزامنة كمجموعة فرعية من
AbstractThreadedSyncAdapter
وتثبيتها كجزء من تطبيق Android. يتعرّف النظام على أداة المزامنة من خلال العناصر الموجودة في بيان التطبيق، ومن خلال ملف XML خاص يشير إليه البيان. يحدّد ملف XML نوع الحساب الخاص بالخدمة على الإنترنت والسلطة الخاصة بمقدّم المحتوى، وهما معًا يحدّدان المحوّل بشكل فريد. لا يصبح محوّل المزامنة نشطًا إلا بعد أن يضيف المستخدم حسابًا لنوع حساب محوّل المزامنة ويُفعّل المزامنة لموفّر المحتوى الذي تتم مزامنته مع محوّل المزامنة. عند هذه النقطة، يبدأ النظام في إدارة المحوّل،
ويستدعيه حسب الحاجة للمزامنة بين موفّر المحتوى والخادم.
ملاحظة: يتيح استخدام نوع حساب كجزء من تعريف أداة المزامنة للنظام رصد أدوات المزامنة التي تصل إلى خدمات مختلفة من المؤسسة نفسها وتجميعها معًا. على سبيل المثال، تتضمّن جميع أدوات مزامنة خدمات Google على الإنترنت نوع الحساب نفسه com.google
. عندما يضيف المستخدمون حساب Google إلى أجهزتهم، يتم إدراج جميع أدوات مزامنة البيانات المثبَّتة لخدمات Google معًا، وتتم مزامنة كل أداة مزامنة بيانات مُدرَجة مع مقدّم محتوى مختلف على الجهاز.
بما أنّ معظم الخدمات تتطلّب من المستخدمين إثبات هويتهم قبل الوصول إلى البيانات، يوفّر نظام التشغيل Android إطار عمل للمصادقة يشبه إطار عمل أداة المزامنة، وغالبًا ما يتم استخدامهما معًا. يستخدم إطار عمل المصادقة أدوات مصادقة إضافية هي فئات فرعية من AbstractAccountAuthenticator
. يتحقّق تطبيق المصادقة من هوية المستخدم باتّباع الخطوات التالية:
- يجمع اسم المستخدم أو كلمة المرور أو معلومات مشابهة (بيانات الاعتماد الخاصة بالمستخدم).
- إرسال بيانات الاعتماد إلى الخدمة
- تفحص هذه السمة ردّ الخدمة.
إذا كانت الخدمة تقبل بيانات الاعتماد، يمكن لأداة المصادقة تخزين بيانات الاعتماد لاستخدامها لاحقًا. بسبب إطار عمل المصادقة الخاص بالإضافات، يمكن أن يوفّر AccountManager
إمكانية الوصول إلى أي رموز مصادقة يتيحها تطبيق المصادقة ويختار عرضها، مثل رموز مصادقة OAuth2.
على الرغم من أنّ المصادقة ليست مطلوبة، إلا أنّ معظم خدمات جهات الاتصال تستخدمها. ومع ذلك، لست ملزمًا باستخدام إطار عمل مصادقة Android لإجراء المصادقة.
تنفيذ محوّل المزامنة
لتنفيذ أداة مزامنة لموفّر جهات الاتصال، عليك أولاً إنشاء تطبيق Android يتضمّن ما يلي:
-
أحد مكونات
Service
التي تستجيب لطلبات النظام بالربط بمحول المزامنة. -
عندما يريد النظام تنفيذ عملية مزامنة، يستدعي الطريقة
onBind()
الخاصة بالخدمة للحصول علىIBinder
لمحول المزامنة. يتيح ذلك للنظام إجراء عمليات استدعاء متعددة العمليات لطُرق المحوّل. -
محوّل المزامنة الفعلي، الذي تم تنفيذه كفئة فرعية ملموسة من
AbstractThreadedSyncAdapter
. -
تتولّى هذه الفئة مهمة تنزيل البيانات من الخادم وتحميل البيانات من الجهاز وحلّ التعارضات. يتم تنفيذ العمل الرئيسي للمحوّل في الطريقة
onPerformSync()
. يجب إنشاء مثيل لهذه الفئة كعنصر فردي. -
فئة فرعية من
Application
-
يعمل هذا الصف كمصنع لنمط التصميم المفرد لمحوّل المزامنة. استخدِم طريقة
onCreate()
لإنشاء مثيل لمحول المزامنة، وقدِّم طريقة "getter" ثابتة لعرض العنصر الفردي إلى طريقةonBind()
الخاصة بخدمة محول المزامنة. -
اختياري: أحد مكونات
Service
التي تستجيب للطلبات الواردة من النظام بشأن مصادقة المستخدم.
تبدأ -
AccountManager
هذه الخدمة لبدء عملية المصادقة. تنشئ طريقةonCreate()
الخاصة بالخدمة كائن مصادقة. عندما يريد النظام مصادقة حساب مستخدم لمحوّل المزامنة الخاص بالتطبيق، يستدعي الطريقةonBind()
الخاصة بالخدمة للحصول علىIBinder
للمصادقة. يتيح ذلك للنظام إجراء عمليات طلب من عدّة عمليات إلى طرق المصادقة. -
اختياري: فئة فرعية ملموسة من
AbstractAccountAuthenticator
تعالج طلبات المصادقة. -
يوفر هذا الصف طرقًا يستدعيها
AccountManager
للمصادقة على بيانات اعتماد المستخدم مع الخادم. تختلف تفاصيل عملية المصادقة بشكل كبير استنادًا إلى تكنولوجيا الخادم المستخدَمة. يجب الرجوع إلى مستندات برنامج الخادم لمعرفة المزيد عن المصادقة. - ملفات XML التي تحدد محوّل المزامنة وبرنامج المصادقة للنظام
-
يتم تحديد مكوّنات خدمة المصادقة ومهايئ المزامنة الموضّحة سابقًا في
عناصر
<service>
في بيان التطبيق. تحتوي هذه العناصر على عناصر ثانوية<meta-data>
تقدّم بيانات محدّدة إلى النظام:-
يشير العنصر
<meta-data>
لخدمة محوّل المزامنة إلى ملف XML res/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 (كائن ثنائي كبير).
- تمثّل هذه السمة الصورة بتنسيق ثنائي، وقد غيّر مقدّم الخدمة حجمها لتخزينها وعرضها. يتوفّر هذا العمود للتوافق مع الإصدارات السابقة من Contacts Provider التي كانت تستخدمه لتخزين الصور. ومع ذلك، في الإصدار الحالي، لا يجب استخدام هذا العمود لتخزين الصور. بدلاً من ذلك، استخدِم إما android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID أو android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (كلاهما موضّح في النقاط التالية) لتخزين الصور في ملف. يحتوي هذا العمود الآن على صورة مصغّرة من الصورة، ويمكن قراءتها.
- android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID
-
معرّف رقمي لصورة جهة اتصال أولية أضِف هذه القيمة إلى الثابت
DisplayPhoto.CONTENT_URI
للحصول على معرّف URI للمحتوى يشير إلى ملف صورة واحد، ثم استدعِ الدالةopenAssetFileDescriptor()
للحصول على معرّف لملف الصورة. - android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI
-
معرّف موارد منتظم للمحتوى يشير مباشرةً إلى ملف الصورة الذي يمثّله هذا الصف.
اتّصِل بالرقم
openAssetFileDescriptor()
باستخدام معرّف الموارد الموحّد هذا للحصول على معرّف لملف الصورة.
استخدام جداول "خلاصة الوسائط الاجتماعية"
تعمل هذه الجداول بالطريقة نفسها التي تعمل بها الجداول الرئيسية الأخرى في "موفّر جهات الاتصال"، باستثناء ما يلي:
- تتطلّب هذه الجداول أذونات وصول إضافية. ولقراءة البيانات من هذه المصادر، يجب أن يحصل تطبيقك على الإذن 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. يمكنك ترك جميع الوسيطات الأخرى غير معرّف الموارد المنتظم (URI) للمحتوى مضبوطًا على
null
. يعرض طلب البحث Cursor يحتوي على صف واحد، مع العمود الفردي android.provider.ContactsContract.StreamItems#MAX_ITEMS.
يحدّد الصف android.provider.ContactsContract.StreamItems.StreamItemPhotos جدولاً فرعيًا من android.provider.ContactsContract.StreamItemPhotos يحتوي على صفوف الصور لعنصر واحد من عناصر ساحة المشاركات.
التفاعلات مع خلاصة الوسائط الاجتماعية
توفّر بيانات خلاصة الشبكات الاجتماعية التي يديرها "مزوّد جهات الاتصال"، بالإضافة إلى تطبيق جهات الاتصال على الجهاز، طريقة فعّالة لربط نظام الشبكات الاجتماعية بجهات الاتصال الحالية. تتوفّر الميزات التالية:
- من خلال مزامنة خدمة الشبكات الاجتماعية مع "موفّر جهات الاتصال" باستخدام أداة مزامنة، يمكنك استرداد النشاط الأخير لجهات اتصال المستخدم وتخزينه في جدولَي android.provider.ContactsContract.StreamItems وandroid.provider.ContactsContract.StreamItemPhotos لاستخدامه لاحقًا.
- بالإضافة إلى المزامنة العادية، يمكنك تفعيل أداة المزامنة لاسترداد بيانات إضافية عندما يختار المستخدم جهة اتصال لعرضها. يتيح ذلك لمحوّل المزامنة استرداد صور عالية الدقة وأحدث عناصر البث لجهة الاتصال.
- من خلال تسجيل إشعار في تطبيق جهات الاتصال على الجهاز و"مزوّد جهات الاتصال"، يمكنك تلقّي هدف عندما يتم عرض جهة اتصال، وعندئذٍ يمكنك تعديل حالة جهة الاتصال من خدمتك. قد يكون هذا الأسلوب أسرع ويستخدم معدل نقل بيانات أقل من إجراء مزامنة كاملة باستخدام أداة مزامنة.
- يمكن للمستخدمين إضافة جهة اتصال إلى خدمة الشبكات الاجتماعية أثناء الاطّلاع على جهة الاتصال في تطبيق جهات الاتصال على الجهاز. يمكنك تفعيل هذه الميزة من خلال ميزة "دعوة جهة اتصال"، والتي يتم تفعيلها من خلال الجمع بين نشاط يضيف جهة اتصال حالية إلى شبكتك، وملف XML يوفّر لتطبيق جهات الاتصال على الجهاز و"مزوّد جهات الاتصال" تفاصيل تطبيقك.
تتم مزامنة عناصر البث مع "مقدّم خدمة جهات الاتصال" بشكل منتظم، كما هو الحال مع عمليات المزامنة الأخرى. لمزيد من المعلومات حول المزامنة، راجِع القسم محوّلات المزامنة الخاصة بموفّر جهات الاتصال. سيتم تناول موضوعَي تسجيل الإشعارات ودعوة جهات الاتصال في القسمَين التاليَين.
تسجيل معالج طرق عرض الشبكات الاجتماعية
لتسجيل أداة المزامنة لتلقّي إشعارات عندما يعرض المستخدم جهة اتصال تتم إدارتها من خلال أداة المزامنة، اتّبِع الخطوات التالية:
-
أنشئ ملفًا باسم
contacts.xml
في دليلres/xml/
الخاص بمشروعك. إذا كان لديك هذا الملف، يمكنك تخطّي هذه الخطوة. -
في هذا الملف، أضِف العنصر
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. إذا كان هذا العنصر متوفّرًا، يمكنك تخطّي هذه الخطوة. -
لتسجيل خدمة يتم إعلامها عندما يفتح المستخدم صفحة تفاصيل جهة اتصال في تطبيق جهات الاتصال على الجهاز، أضِف السمة
viewContactNotifyService="serviceclass"
إلى العنصر، حيثserviceclass
هو اسم الفئة المؤهَّل بالكامل للخدمة التي يجب أن تتلقّى الغرض من تطبيق جهات الاتصال على الجهاز. بالنسبة إلى خدمة الإشعارات، استخدِم فئة توسّعIntentService
، للسماح للخدمة بتلقّي الأهداف. تحتوي البيانات في Intent الوارد على معرّف الموارد المنتظم (URI) الخاص بجهة الاتصال الأولية التي نقر عليها المستخدم. من خدمة الإشعارات، يمكنك الربط بمحوّل المزامنة ثم استدعاؤه لتعديل بيانات جهة الاتصال الأولية.
لتسجيل نشاط يتم تنفيذه عندما ينقر المستخدم على عنصر أو صورة في الخلاصة أو كليهما، اتّبِع الخطوات التالية:
-
أنشئ ملفًا باسم
contacts.xml
في دليلres/xml/
الخاص بمشروعك. إذا كان لديك هذا الملف، يمكنك تخطّي هذه الخطوة. -
في هذا الملف، أضِف العنصر
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. إذا كان هذا العنصر متوفّرًا، يمكنك تخطّي هذه الخطوة. -
لتسجيل أحد أنشطتك للتعامل مع نقر المستخدم على عنصر بث في تطبيق جهات الاتصال على الجهاز، أضِف السمة
viewStreamItemActivity="activityclass"
إلى العنصر، حيثactivityclass
هو اسم الفئة المؤهَّل بالكامل للنشاط الذي يجب أن يتلقّى الغرض من تطبيق جهات الاتصال على الجهاز. -
لتسجيل أحد أنشطتك للتعامل مع نقر المستخدم على صورة بث في تطبيق جهات الاتصال على الجهاز، أضِف السمة
viewStreamItemPhotoActivity="activityclass"
إلى العنصر، حيثactivityclass
هو اسم الفئة المؤهَّل بالكامل للنشاط الذي يجب أن يتلقّى الغرض من تطبيق جهات الاتصال على الجهاز.
يتم وصف العنصر <ContactsAccountType>
بمزيد من التفصيل في قسم العنصر<ContactsAccountType>.
يحتوي الغرض الوارد على معرّف الموارد المنتظم (URI) للمحتوى الخاص بالعنصر أو الصورة التي نقر عليها المستخدم. للحصول على أنشطة منفصلة للعناصر النصية والصور، استخدِم السمتَين معًا في الملف نفسه.
التفاعل مع خدمة شبكة التواصل الاجتماعي
لا يحتاج المستخدمون إلى مغادرة تطبيق جهات الاتصال على الجهاز لدعوة جهة اتصال إلى موقعك الإلكتروني للتواصل الاجتماعي. بدلاً من ذلك، يمكنك أن تطلب من تطبيق جهات الاتصال على الجهاز إرسال غرض لدعوة جهة الاتصال إلى أحد أنشطتك. لإعداد هذه الميزة، اتّبِع الخطوات التالية:
-
أنشئ ملفًا باسم
contacts.xml
في دليلres/xml/
الخاص بمشروعك. إذا كان لديك هذا الملف، يمكنك تخطّي هذه الخطوة. -
في هذا الملف، أضِف العنصر
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android">
. إذا كان هذا العنصر متوفّرًا، يمكنك تخطّي هذه الخطوة. -
أضِف السمات التالية:
inviteContactActivity="activityclass"
-
inviteContactActionLabel="@string/invite_action_label"
activityclass
هي اسم الفئة المؤهَّل بالكامل للنشاط الذي يجب أن يتلقّى الغرض. قيمةinvite_action_label
هي سلسلة نصية يتم عرضها في قائمة إضافة اتصال في تطبيق جهات الاتصال على الجهاز.
ملاحظة: ContactsSource
هو اسم علامة تم إيقافها نهائيًا ويجب استخدام ContactsAccountType
بدلاً منه.
مرجع contacts.xml
يحتوي الملف contacts.xml
على عناصر XML تتحكّم في تفاعل محوّل المزامنة والتطبيق مع تطبيق "جهات الاتصال" و"موفّر جهات الاتصال". يتم وصف هذه العناصر في الأقسام التالية.
العنصر <ContactsAccountType>
يتحكّم العنصر <ContactsAccountType>
في تفاعل تطبيقك مع تطبيق جهات الاتصال. تتضمّن هذه الدالة بنية الجملة التالية:
<ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android" inviteContactActivity="activity_name" inviteContactActionLabel="invite_command_text" viewContactNotifyService="view_notify_service" viewGroupActivity="group_view_activity" viewGroupActionLabel="group_action_text" viewStreamItemActivity="viewstream_activity_name" viewStreamItemPhotoActivity="viewphotostream_activity_name">
مضمّنة في:
res/xml/contacts.xml
يمكن أن يحتوي على:
<ContactsDataKind>
الوصف:
توضّح هذه السمة عناصر Android وتصنيفات واجهة المستخدم التي تتيح للمستخدمين دعوة أحد جهات اتصالهم إلى شبكة تواصل اجتماعي، وإرسال إشعارات إلى المستخدمين عند تعديل أحد خلاصات شبكات التواصل الاجتماعي الخاصة بهم، وما إلى ذلك.
يُرجى العِلم أنّ بادئة السمة android:
ليست ضرورية لسمات <ContactsAccountType>
.
السمات:
inviteContactActivity
- اسم الفئة المؤهَّل بالكامل للنشاط في تطبيقك الذي تريد تفعيله عندما يختار المستخدم إضافة اتصال من تطبيق جهات الاتصال على الجهاز.
inviteContactActionLabel
-
سلسلة نصية يتم عرضها للنشاط المحدّد في
inviteContactActivity
، في قائمة إضافة اتصال على سبيل المثال، يمكنك استخدام السلسلة "متابعة في شبكتي". يمكنك استخدام معرّف لمورد سلسلة لهذا التصنيف. viewContactNotifyService
- اسم الفئة المؤهَّل بالكامل لخدمة في تطبيقك يجب أن تتلقّى إشعارات عندما يعرض المستخدم جهة اتصال. يتم إرسال هذا الإشعار من خلال تطبيق جهات الاتصال على الجهاز، وهو يتيح لتطبيقك تأجيل العمليات التي تتطلّب كمية كبيرة من البيانات إلى حين الحاجة إليها. على سبيل المثال، يمكن لتطبيقك الاستجابة لهذا الإشعار من خلال قراءة وعرض صورة جهة الاتصال العالية الدقة وأحدث عناصر خلاصة وسائل التواصل الاجتماعي. يتم وصف هذه الميزة بمزيد من التفصيل في القسم التفاعلات مع خلاصة الوسائط الاجتماعية.
viewGroupActivity
- الاسم المؤهَّل بالكامل لفئة نشاط في تطبيقك يمكنه عرض معلومات المجموعة. عندما ينقر المستخدم على تصنيف المجموعة في تطبيق جهات الاتصال على الجهاز، يتم عرض واجهة المستخدم لهذا النشاط.
viewGroupActionLabel
-
التصنيف الذي يعرضه تطبيق جهات الاتصال لعنصر تحكّم في واجهة المستخدم يتيح
للمستخدم الاطّلاع على المجموعات في تطبيقك.
يُسمح باستخدام معرّف مورد سلسلة لهذه السمة.
viewStreamItemActivity
- اسم الفئة المؤهَّل بالكامل لنشاط في تطبيقك يطلقه تطبيق جهات الاتصال على الجهاز عندما ينقر المستخدم على عنصر بث لجهة اتصال أولية.
viewStreamItemPhotoActivity
- اسم الفئة المؤهَّل بالكامل لنشاط في تطبيقك يطلقه تطبيق جهات الاتصال على الجهاز عندما ينقر المستخدم على صورة في عنصر الخلاصة لجهة اتصال أولية.
عنصر <ContactsDataKind>
يتحكّم العنصر <ContactsDataKind>
في عرض صفوف البيانات المخصّصة لتطبيقك في واجهة مستخدم تطبيق "جهات الاتصال". تتضمّن هذه الدالة بنية الجملة التالية:
<ContactsDataKind android:mimeType="MIMEtype" android:icon="icon_resources" android:summaryColumn="column_name" android:detailColumn="column_name">
مضمّنة في:
<ContactsAccountType>
الوصف:
استخدِم هذا العنصر لجعل تطبيق جهات الاتصال يعرض محتوى صف بيانات مخصّص كجزء من تفاصيل جهة اتصال أولية. يمثّل كل عنصر فرعي <ContactsDataKind>
من <ContactsAccountType>
نوعًا من صفوف البيانات المخصّصة التي يضيفها محوّل المزامنة إلى جدول ContactsContract.Data
. أضِف عنصر <ContactsDataKind>
واحدًا لكل نوع MIME مخصّص تستخدمه. لست مضطرًا إلى إضافة العنصر إذا كان لديك صف بيانات مخصّص لا تريد عرض البيانات فيه.
السمات:
android:mimeType
-
نوع MIME المخصّص الذي حدّدته لأحد أنواع صفوف البيانات المخصّصة في
جدول
ContactsContract.Data
. على سبيل المثال، يمكن أن تكون القيمةvnd.android.cursor.item/vnd.example.locationstatus
نوع MIME مخصّصًا لصف بيانات يسجّل آخر موقع جغرافي معروف لجهة اتصال. android:icon
- هو أحد موارد الرسومات القابلة للرسم في نظام التشغيل Android الذي يعرضه تطبيق "جهات الاتصال" بجانب بياناتك. استخدِم هذا الحقل لإعلام المستخدم بأنّ البيانات واردة من خدمتك.
android:summaryColumn
- اسم العمود الخاص بالقيمة الأولى من القيمتَين اللتين تم استرجاعهما من صف البيانات. يتم عرض القيمة في السطر الأول من الإدخال لصف البيانات هذا. يُفترض استخدام السطر الأول كملخّص للبيانات، ولكن هذا الإجراء اختياري. راجِع أيضًا android:detailColumn.
android:detailColumn
-
اسم العمود الخاص بالقيمة الثانية من القيمتَين اللتين تم استرجاعهما من صف البيانات. يتم عرض القيمة
كسطر ثانٍ لإدخال صف البيانات هذا. يمكنك الاطّلاع أيضًا على
android:summaryColumn
.
ميزات إضافية لمقدّم جهات الاتصال
بالإضافة إلى الميزات الرئيسية الموضّحة في الأقسام السابقة، يوفّر "مقدّم جهات الاتصال" الميزات المفيدة التالية للتعامل مع بيانات جهات الاتصال:
- مجموعات جهات الاتصال
- ميزات الصور
مجموعات جهات الاتصال
يمكن لموفّر جهات الاتصال اختياريًا تصنيف مجموعات جهات الاتصال ذات الصلة باستخدام بيانات المجموعة. إذا كان الخادم المرتبط بحساب مستخدم يريد الاحتفاظ بالمجموعات، يجب أن ينقل محوّل المزامنة لنوع حساب الحساب بيانات المجموعات بين "مزوّد جهات الاتصال" والخادم. عندما يضيف المستخدمون جهة اتصال جديدة إلى الخادم ثم يضعون جهة الاتصال هذه في مجموعة جديدة، يجب أن يضيف محوّل المزامنة المجموعة الجديدة إلى جدول ContactsContract.Groups
. يتم تخزين المجموعة أو المجموعات التي تنتمي إليها جهة اتصال أولية في جدول ContactsContract.Data
باستخدام نوع MIME ContactsContract.CommonDataKinds.GroupMembership
.
إذا كنت تصمّم أداة مزامنة ستضيف بيانات جهات الاتصال الأولية من الخادم إلى "مزوّد جهات الاتصال"، ولم تكن تستخدم المجموعات، عليك إخبار "المزوّد" بجعل بياناتك مرئية. في الرمز البرمجي الذي يتم تنفيذه عندما يضيف مستخدم حسابًا إلى الجهاز، عدِّل الصف ContactsContract.Settings
الذي يضيفه "مقدّم خدمة جهات الاتصال" للحساب. في هذا الصف، اضبط قيمة العمود Settings.UNGROUPED_VISIBLE
على 1. عند إجراء ذلك، سيجعل "موفّر جهات الاتصال" بيانات جهات الاتصال مرئية دائمًا، حتى إذا لم تستخدم المجموعات.
صور جهات الاتصال
يخزّن الجدول ContactsContract.Data
الصور كصفوف بنوع MIME
Photo.CONTENT_ITEM_TYPE
. يرتبط عمود CONTACT_ID
في الصف بعمود _ID
في جهة الاتصال الأولية التي ينتمي إليها.
يحدّد الصف ContactsContract.Contacts.Photo
جدولاً فرعيًا من ContactsContract.Contacts
يحتوي على معلومات الصور الخاصة بصورة جهة الاتصال الأساسية، وهي الصورة الأساسية لجهة الاتصال الأساسية غير المعالجة. وبالمثل، يحدّد الصف ContactsContract.RawContacts.DisplayPhoto
جدولاً فرعياً من ContactsContract.RawContacts
يحتوي على معلومات الصور الخاصة بالصورة الأساسية لجهة اتصال أولية.
تحتوي المستندات المرجعية الخاصة بالرمزين ContactsContract.Contacts.Photo
وContactsContract.RawContacts.DisplayPhoto
على أمثلة حول استرداد معلومات الصور. لا يتوفّر فئة ملائمة لاسترداد الصورة المصغّرة الأساسية لجهة اتصال أولية، ولكن يمكنك إرسال طلب بحث إلى جدول ContactsContract.Data
، واختيار _ID
لجهة الاتصال الأولية وPhoto.CONTENT_ITEM_TYPE
وعمود IS_PRIMARY
للعثور على صف الصورة الأساسية لجهة الاتصال الأولية.
قد تتضمّن بيانات الخلاصة الاجتماعية الخاصة بأحد المستخدمين صورًا أيضًا. ويتم تخزينها في جدول android.provider.ContactsContract.StreamItemPhotos، الذي يتم وصفه بمزيد من التفصيل في القسم صور خلاصة الوسائط الاجتماعية.