يدير موفر المحتوى إمكانية الوصول إلى مستودع مركزي للبيانات. مقدّم خدمة جزءًا من تطبيق Android، والذي يوفر غالبًا واجهة مستخدم خاصة به للعمل مع البيانات. ومع ذلك، يتم استخدام مقدمي المحتوى بشكل أساسي بواسطة التطبيقات التي يمكنها الوصول إلى الموفِّر باستخدام عنصر عميل موفّر يقدّم مقدّمو الخدمات ويوفّر عملاء الموفّرين واجهة متسقة وعادية للبيانات تعالج أيضًا الاتصال البيني للعمليات والوصول الآمن إلى البيانات.
عادةً ما تعمل مع موفّري المحتوى في أحد حالتين: تنفيذ المستخدم للوصول إلى موفِّر محتوى حالي في تطبيق آخر أو إنشاء موفر محتوى جديد في تطبيقك لمشاركة البيانات مع التطبيقات الأخرى.
هذه الصفحة أساسيات العمل مع موفّري المحتوى الحاليين للتعرف على تنفيذ موفري المحتوى في تطبيقاتك، راجع إنشاء موفّر محتوى
يتناول هذا الموضوع ما يلي:
- آلية عمل موفّري المحتوى
- واجهة برمجة التطبيقات التي تستخدمها لاسترداد البيانات من موفّر محتوى.
- واجهة برمجة التطبيقات التي تستخدمها لإدراج البيانات أو تعديلها أو حذفها في أحد موفّري المحتوى
- ميزات أخرى لواجهة برمجة التطبيقات تُسهل العمل مع موفّري الخدمات
نظرة عامة
يقدم موفر المحتوى البيانات إلى التطبيقات الخارجية في صورة جدول واحد أو أكثر مشابهة للجداول الموجودة في قاعدة بيانات ارتباطية. يمثل الصف مثيلاً من نوع ما البيانات التي يجمعها الموفر، ويمثل كل عمود في الصف جزءًا فرديًا من البيانات التي تم جمعها على سبيل المثال.
ينسق موفر المحتوى للوصول إلى طبقة تخزين البيانات في تطبيقك عدد واجهات برمجة التطبيقات والمكونات المختلفة. كما هو موضح في الشكل 1، تشمل هذه ما يلي:
- مشاركة الوصول إلى بيانات تطبيقك مع تطبيقات أخرى
- إرسال البيانات إلى تطبيق مصغّر
- عرض اقتراحات البحث المخصّص لتطبيقك من خلال البحث
إطار عمل باستخدام
SearchRecentSuggestionsProvider
- مزامنة بيانات التطبيق مع خادمك باستخدام تنفيذ
AbstractThreadedSyncAdapter
- جارٍ تحميل البيانات في واجهة المستخدم باستخدام
CursorLoader
![العلاقة بين موفّر المحتوى والمكونات الأخرى.](https://developer.android.com/static/guide/topics/providers/images/content-provider-tech-stack.png?authuser=19&hl=ar)
الشكل 1. العلاقة بين موفّر المحتوى والمكونات الأخرى.
الوصول إلى مقدّم خدمة
عندما تريد الوصول إلى البيانات في أحد موفّري المحتوى، يمكنك استخدام
عنصر واحد (ContentResolver
) في تطبيقك
Context
للتواصل مع مقدّم الخدمة كعميل. تشير رسالة الأشكال البيانية
يتصل كائن ContentResolver
بعنصر الموفِّر، وهو
لفئة تنفذ ContentProvider
.
مزوِّد الخدمة
ويتلقى طلبات البيانات من العملاء، وينفذ الإجراء المطلوب، ثم يعرض
نتائجك. يتضمن هذا الكائن طرقًا تتطلب طرقًا ذات أسماء متطابقة في كائن الموفر،
تمثّل هذه السمة إحدى الفئات الفرعية الملموسة للسمة ContentProvider
. تشير رسالة الأشكال البيانية
توفِّر طرق ContentResolver
البيانات الأساسية
CRUD (الإنشاء والاسترداد والتحديث والحذف) لوظائف مساحة التخزين الدائمة.
هناك نمط شائع للوصول إلى ContentProvider
من واجهة المستخدم الخاصة بك يستخدم
CursorLoader
لتشغيل طلب بحث غير متزامن في الخلفية. تشير رسالة الأشكال البيانية
يستدعي Activity
أو Fragment
في واجهة المستخدم الخاصة بك
CursorLoader
إلى الاستعلام، والذي بدوره يحصل على
ContentProvider
باستخدام ContentResolver
.
ويسمح هذا الإجراء بإبقاء واجهة المستخدم متاحة للمستخدم أثناء تنفيذ طلب البحث. هذا النمط يتضمن التفاعل بين عدد من الكائنات المختلفة، بالإضافة إلى العنصر الأساسي لآلية التخزين، كما هو موضح في الشكل 2.
![التفاعل بين ContentProvider والفئات الأخرى ومساحة التخزين.](https://developer.android.com/static/guide/topics/providers/images/content-provider-interaction.png?authuser=19&hl=ar)
الشكل 2. التفاعل بين ContentProvider
والصفوف الأخرى ومساحة التخزين.
ملاحظة: للوصول إلى أحد مقدّمي الخدمة، يجب عادةً أن يطلب تطبيقك الأذونات في ملف البيان. يتم وصف نمط التطوير هذا بمزيد من التفصيل في أذونات موفّر المحتوى
أحد مزودي الخدمة المدمجين في نظام Android الأساسي هو مزود قاموس المستخدم، الذي تخزن الكلمات غير القياسية التي يرغب المستخدم في الاحتفاظ بها. يوضح الجدول 1 ما قد تبدو البيانات في جدول هذا المزود:
الجدول 1: نموذج جدول قاموس المستخدم.
ألعاب الكلمات | الرقم التعريفي للتطبيق | النشر | اللغة | _ID |
---|---|---|---|---|
mapreduce |
المستخدم 1 | 100 | en_US | 1 |
precompiler |
المستخدم 14 | 200 | fr_FR | 2 |
applet |
المستخدم 2 | 225 | fr_CA | 3 |
const |
المستخدم 1 | 255 | pt_BR | 4 |
int |
المستخدم 5 | 100 | ar_UK | 5 |
في الجدول 1، يمثل كل صف مثيلاً لكلمة ليست
يمكن العثور عليها في القاموس القياسي. يمثل كل عمود جزءًا من البيانات لتلك الكلمة، مثل
مكان حدوثه لأول مرة. رؤوس الأعمدة هي أسماء أعمدة يتم تخزينها في
المزود. وبالتالي، للإشارة إلى لغة صف، عليك مثلاً الرجوع إلى عمود locale
. بالنسبة
هذا الموفر، يعمل عمود _ID
كعمود مفتاح أساسي
يحافظ عليه المزود تلقائيًا.
للحصول على قائمة بالكلمات ولغاتها المحلية من مزود قاموس المستخدم،
تتصل بـ ContentResolver.query()
.
تستدعي طريقة query()
السمة
ContentProvider.query()
التي تحددها السمة
موفِّر قاموس المستخدم تُظهر سطور التعليمة البرمجية التالية
الاتصال عبر ContentResolver.query()
:
Kotlin
// Queries the UserDictionary and returns results cursor = contentResolver.query( UserDictionary.Words.CONTENT_URI, // The content URI of the words table projection, // The columns to return for each row selectionClause, // Selection criteria selectionArgs.toTypedArray(), // Selection criteria sortOrder // The sort order for the returned rows )
Java
// Queries the UserDictionary and returns results cursor = getContentResolver().query( UserDictionary.Words.CONTENT_URI, // The content URI of the words table projection, // The columns to return for each row selectionClause, // Selection criteria selectionArgs, // Selection criteria sortOrder); // The sort order for the returned rows
يوضح الجدول 2 كيف يمكن أن تؤدي الوسيطات
تتطابق query(Uri,projection,selection,selectionArgs,sortOrder)
مع عبارة SQL SELECT:
الجدول 2: query()
مقارنةً بطلب بحث SQL.
الوسيطة query() |
تحديد الكلمة الرئيسية/المعلمة | ملاحظات |
---|---|---|
Uri |
FROM table_name |
يربط Uri بالجدول في موفِّر الخدمة الذي يحمل اسم table_name. |
projection |
col,col,col,... |
projection عبارة عن مصفوفة من الأعمدة التي يتم تضمينها لكل صف.
استرداده.
|
selection |
WHERE col = value |
تحدّد السمة selection معايير اختيار الصفوف. |
selectionArgs |
ما مِن مكافئ مماثل. تحل وسيطات الاختيار محل العناصر النائبة ? في
عبارة الاختيار.
|
|
sortOrder |
ORDER BY col,col,... |
تحدّد السمة sortOrder الترتيب الذي تظهر به الصفوف في الصفحات المعروضة.
Cursor
|
معرّفات الموارد المنتظمة (URI) للمحتوى
معرّف الموارد المنتظم (URI) للمحتوى هو معرّف موارد منتظم (URI) يحدّد البيانات في أحد الموفّرين. معرّفات الموارد المنتظمة (URI) للمحتوى تتضمّن الاسم الرمزي لموفّر الخدمة بالكامل، سلطته، بالإضافة إلى اسم يشير إلى جدول - مسار. عند الاتصال العميل للوصول إلى جدول في الموفر، فإن معرف الموارد المنتظم للمحتوى للجدول هو أحد الوسيطات.
في السطور السابقة من التعليمة البرمجية، يكون الثابت
يحتوي CONTENT_URI
على معرّف الموارد المنتظم (URI) لمحتوى
جدول Words
لمزود قاموس المستخدم. ContentResolver
تحليل مرجع عنوان URI ويستخدمه لحلّ الموفِّر عن طريق
يقارن بين السلطة وجدول النظام لمزودي الخدمة المعروفين. تشير رسالة الأشكال البيانية
يمكن لـ ContentResolver
بعد ذلك نقل وسيطات طلب البحث إلى القيمة الصحيحة
المستخدم.
يستخدم ContentProvider
جزء المسار من معرّف الموارد المنتظم (URI) للمحتوى لاختيار
الوصول إليه. عادةً ما يكون لدى الموفر مسار لكل جدول يعرضه.
في سطور الرمز السابقة، يكون معرّف الموارد المنتظم (URI) الكامل للجدول Words
هو:
content://user_dictionary/words
- سلسلة
content://
هي المخطط، وهو موجود دائمًا ويحدد هذا باعتباره معرف موارد منتظم (URI) للمحتوى. - تمثّل السلسلة
user_dictionary
مرجع الموفّر. - السلسلة
words
هي مسار الجدول.
يتيح لك العديد من مقدّمي الخدمة الوصول إلى صف واحد في جدول من خلال إلحاق قيمة معرّف.
إلى نهاية عنوان URI. على سبيل المثال، لاسترداد صف يكون _ID
فيه
4
من مزود قاموس المستخدم، يمكنك استخدام معرف الموارد المنتظم (URI) هذا للمحتوى:
Kotlin
val singleUri: Uri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI, 4)
Java
Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
غالبًا ما تستخدم قيم المعرّفات عند استرداد مجموعة من الصفوف ثم تريد تعديلها أو حذفها. واحد منها.
ملاحظة: الصفّان Uri
وUri.Builder
يحتوي على طرق ملائمة لإنشاء كائنات معرف موارد منتظم (URI) جيدة الشكل من السلاسل. تشير رسالة الأشكال البيانية
تحتوي الفئة ContentUris
على طرق ملائمة لإلحاق قيم المعرّفات بـ
معرف موارد منتظم (URI). يستخدم المقتطف السابق withAppendedId()
لإلحاق معرّف بمعرّف الموارد المنتظم (URI) الخاص بمحتوى موفّر قاموس المستخدم.
استرداد البيانات من المزود
يصف هذا القسم كيفية استرداد البيانات من أحد الموفّرين باستخدام "موفّر قاموس المستخدم" كمثال.
وللتوضيح، تقوم مقتطفات الرمز في هذا القسم باستدعاء
ContentResolver.query()
في سلسلة واجهة المستخدم. ضِمن
مع ذلك، يتم إجراء طلبات البحث بشكل غير متزامن في سلسلة محادثات منفصلة. يمكنك
استخدام الفئة CursorLoader
، والموصوفة
بشكلٍ أكثر تفصيلاً في
دليل التحميلات. كما أن سطور الرمز هي مقتطفات فقط. ولا تعرض صورة كاملة
التطبيق.
لاسترداد البيانات من مقدّم خدمة، اتّبِع الخطوات الأساسية التالية:
- اطلب إذن الوصول للقراءة إلى الموفّر.
- حدّد الرمز الذي يرسل طلب بحث إلى الموفِّر.
طلب إذن بالقراءة
لاسترداد البيانات من أحد الموفّرين، يحتاج تطبيقك إلى إذن بالقراءة
المستخدم. لا يمكنك طلب هذا الإذن في وقت التشغيل. بدلاً من ذلك، يجب عليك تحديد أن
يجب الحصول على هذا الإذن في ملف البيان، وذلك باستخدام
<uses-permission>
واسم الإذن المحدد من قِبل
المستخدم.
عندما تحدد هذا العنصر في ملف البيان، فأنت تطلب هذا للحصول على إذن لاستخدام تطبيقك. عندما يثبّت المستخدمون تطبيقك، فإنهم يمنحون ضمنًا لهذا الطلب.
للعثور على الاسم الدقيق لإذن الوصول للقراءة الخاص بالموفِّر الذي تستخدمه، عليك أيضًا بأسماء أذونات الوصول الأخرى التي يستخدمها الموفر، فابحث في ملف التوثيق.
يتم توضيح دور الأذونات في الوصول إلى موفِّري الخدمات بمزيد من التفصيل في أذونات موفّر المحتوى
يحدد موفّر قاموس المستخدم الإذن
android.permission.READ_USER_DICTIONARY
في ملف البيان، ولذلك فإن
على التطبيق الذي يريد القراءة من مقدّم الخدمة طلب هذا الإذن.
إنشاء الاستعلام
الخطوة التالية في استرداد البيانات من الموفر هي إنشاء استعلام. المقتطف التالي بعض المتغيرات للوصول إلى مزود قاموس المستخدم:
Kotlin
// A "projection" defines the columns that are returned for each row private val mProjection: Array<String> = arrayOf( UserDictionary.Words._ID, // Contract class constant for the _ID column name UserDictionary.Words.WORD, // Contract class constant for the word column name UserDictionary.Words.LOCALE // Contract class constant for the locale column name ) // Defines a string to contain the selection clause private var selectionClause: String? = null // Declares an array to contain selection arguments private lateinit var selectionArgs: Array<String>
Java
// A "projection" defines the columns that are returned for each row String[] mProjection = { UserDictionary.Words._ID, // Contract class constant for the _ID column name UserDictionary.Words.WORD, // Contract class constant for the word column name UserDictionary.Words.LOCALE // Contract class constant for the locale column name }; // Defines a string to contain the selection clause String selectionClause = null; // Initializes an array to contain selection arguments String[] selectionArgs = {""};
يوضح المقتطف التالي كيفية استخدام
ContentResolver.query()
، باستخدام قاموس المستخدم
موفّر الخدمة كمثال. يشبه استعلام عميل الموفر استعلام SQL، ويحتوي على
ومجموعة الأعمدة المراد عرضها ومجموعة من معايير الاختيار وترتيب الفرز.
وتُسمى مجموعة الأعمدة التي يعرضها طلب البحث الإسقاط،
فيكون المتغير mProjection
.
يتم تقسيم التعبير الذي يحدد الصفوف المراد استردادها إلى عبارة تحديد
وسيطات التحديد. عبارة التحديد هي مزيج من التعبيرات المنطقية والمنطقية،
وأسماء الأعمدة والقيم. المتغيّر هو mSelectionClause
. إذا قمت بتحديد
المعلمة القابلة للاستبدال ?
بدلاً من قيمة، تسترد طريقة طلب البحث القيمة
من مصفوفة وسيطات التحديد، وهو المتغير mSelectionArgs
.
في المقتطف التالي، إذا لم يُدخل المستخدم أي كلمة، فسيتم تعيين عبارة الاختيار على
null
ويعرض طلب البحث جميع الكلمات الواردة في الموفِّر. إذا أدخل المستخدم
كلمة، يتم تعيين عبارة الاختيار على UserDictionary.Words.WORD + " = ?"
يتم تعيين العنصر الأول من مصفوفة وسيطات التحديد على الكلمة التي يدخلها المستخدم.
Kotlin
/* * This declares a String array to contain the selection arguments. */ private lateinit var selectionArgs: Array<String> // Gets a word from the UI searchString = searchWord.text.toString() // Insert code here to check for invalid or malicious input // If the word is the empty string, gets everything selectionArgs = searchString?.takeIf { it.isNotEmpty() }?.let { selectionClause = "${UserDictionary.Words.WORD} = ?" arrayOf(it) } ?: run { selectionClause = null emptyArray<String>() } // Does a query against the table and returns a Cursor object mCursor = contentResolver.query( UserDictionary.Words.CONTENT_URI, // The content URI of the words table projection, // The columns to return for each row selectionClause, // Either null or the word the user entered selectionArgs, // Either empty or the string the user entered sortOrder // The sort order for the returned rows ) // Some providers return null if an error occurs, others throw an exception when (mCursor?.count) { null -> { /* * Insert code here to handle the error. Be sure not to use the cursor! * You might want to call android.util.Log.e() to log this error. */ } 0 -> { /* * Insert code here to notify the user that the search is unsuccessful. This isn't * necessarily an error. You might want to offer the user the option to insert a new * row, or re-type the search term. */ } else -> { // Insert code here to do something with the results } }
Java
/* * This defines a one-element String array to contain the selection argument. */ String[] selectionArgs = {""}; // Gets a word from the UI searchString = searchWord.getText().toString(); // Remember to insert code here to check for invalid or malicious input // If the word is the empty string, gets everything if (TextUtils.isEmpty(searchString)) { // Setting the selection clause to null returns all words selectionClause = null; selectionArgs[0] = ""; } else { // Constructs a selection clause that matches the word that the user entered selectionClause = UserDictionary.Words.WORD + " = ?"; // Moves the user's input string to the selection arguments selectionArgs[0] = searchString; } // Does a query against the table and returns a Cursor object mCursor = getContentResolver().query( UserDictionary.Words.CONTENT_URI, // The content URI of the words table projection, // The columns to return for each row selectionClause, // Either null or the word the user entered selectionArgs, // Either empty or the string the user entered sortOrder); // The sort order for the returned rows // Some providers return null if an error occurs, others throw an exception if (null == mCursor) { /* * Insert code here to handle the error. Be sure not to use the cursor! You can * call android.util.Log.e() to log this error. * */ // If the Cursor is empty, the provider found no matches } else if (mCursor.getCount() < 1) { /* * Insert code here to notify the user that the search is unsuccessful. This isn't necessarily * an error. You can offer the user the option to insert a new row, or re-type the * search term. */ } else { // Insert code here to do something with the results }
هذا الاستعلام مماثل لعبارة SQL التالية:
SELECT _ID, word, locale FROM words WHERE word = <userinput> ORDER BY word ASC;
في عبارة SQL هذه، يتم استخدام أسماء الأعمدة الفعلية بدلاً من ثوابت فئة العقد.
الحماية من الإدخالات الضارة
إذا كانت البيانات التي يديرها موفّر المحتوى موجودة في قاعدة بيانات SQL، بما في ذلك البيانات الخارجية غير الموثوق بها البيانات إلى عبارات SQL (لغة الاستعلام البنيوية) الأولية إلى إدخال SQL.
ضع في اعتبارك عبارة التحديد التالية:
Kotlin
// Constructs a selection clause by concatenating the user's input to the column name var selectionClause = "var = $mUserInput"
Java
// Constructs a selection clause by concatenating the user's input to the column name String selectionClause = "var = " + userInput;
إذا قمت بذلك، فقد تسمح للمستخدم بتسلسل SQL الضار على عبارة SQL الخاصة بك.
على سبيل المثال، يمكن للمستخدم إدخال "لا شيء؛ إسقاط الجدول *;" لـ mUserInput
، والذي
ينتج عنها عبارة الاختيار var = nothing; DROP TABLE *;
.
نظرًا لأن كعبارة SQL، فقد يتسبب هذا في مسح الموفر لجميع الجداول الموجودة في قاعدة بيانات SQLite الأساسية، ما لم يتم إعداد الموفر لاكتشاف محاولات إدخال SQL.
لتجنُّب هذه المشكلة، يمكنك استخدام عبارة اختيار تستخدم ?
كعنصر قابل للاستبدال.
ومجموعة منفصلة من وسيطات الاختيار. بهذه الطريقة، يُدخل المستخدم
مباشرة بالاستعلام بدلاً من تفسيرها كجزء من عبارة SQL.
ولأنه لا يتم التعامل معه كلغة SQL، لا يمكن لإدخال المستخدم أن يقوم بإدخال لغة SQL ضارة. بدلاً من استخدام
لتضمين إدخال المستخدم، استخدم عبارة التحديد هذه:
Kotlin
// Constructs a selection clause with a replaceable parameter var selectionClause = "var = ?"
Java
// Constructs a selection clause with a replaceable parameter String selectionClause = "var = ?";
يمكنك إعداد مصفوفة وسيطات الاختيار كما يلي:
Kotlin
// Defines a mutable list to contain the selection arguments var selectionArgs: MutableList<String> = mutableListOf()
Java
// Defines an array to contain the selection arguments String[] selectionArgs = {""};
ضع قيمة في مصفوفة وسيطات الاختيار كما يلي:
Kotlin
// Adds the user's input to the selection argument selectionArgs += userInput
Java
// Sets the selection argument to the user's input selectionArgs[0] = userInput;
يشير هذا المصطلح إلى عبارة اختيار تستخدم ?
كمَعلمة قابلة للاستبدال ومصفوفة من
وهي الطريقة المفضلة لتحديد تحديد، حتى إذا لم يكن الموفر
استنادًا إلى قاعدة بيانات SQL.
عرض نتائج طلبات البحث
دائمًا ما تستخدم طريقة العميل ContentResolver.query()
تؤدي إلى إرجاع Cursor
تحتوي على الأعمدة المحددة بواسطة
توقع للصفوف التي تتطابق مع معايير تحديد الاستعلام. حاسمة
يوفّر الكائن Cursor
إذنًا عشوائيًا بقراءة الصفوف والأعمدة.
يحتوي عليها.
باستخدام طرق Cursor
، يمكنك تكرار الصفوف في
النتائج، وتحديد نوع البيانات لكل عمود، والحصول على البيانات من عمود، وفحص
وخصائص النتائج.
بعض عمليات تنفيذ "Cursor
" تلقائيًا
تعديل الكائن عند تغيُّر بيانات مقدّم الخدمة، وتفعيل الطرق في عنصر مراقب
عند تغيير Cursor
أو كليهما.
ملاحظة: يمكن لأي موفِّر حظر الوصول إلى الأعمدة استنادًا إلى طبيعة الذي يقوم بإجراء الاستعلام. على سبيل المثال، يقيّد "موفِّر جهات الاتصال" الوصول إلى بعض الأعمدة حتى لا تُرجعها إلى نشاط أو خدمة.
إذا لم تتطابق أي صفوف مع معايير الاختيار، سيتعين على الموفر
تعرض كائن Cursor
الذي
Cursor.getCount()
هو
0 - وهو مؤشر فارغ.
وفي حال حدوث خطأ داخلي، تعتمد نتائج طلب البحث على الموفِّر المعين. ربما
عرض null
، أو يمكن طرح Exception
.
بما أنّ السمة Cursor
هي قائمة من الصفوف، فإنّها طريقة جيدة لعرض
يتمثل محتوى Cursor
في ربطه بـ ListView
باستخدام SimpleCursorAdapter
.
يعمل المقتطف التالي على إضافة الرمز من المقتطف السابق. إنه ينشئ
كائن SimpleCursorAdapter
يحتوي على Cursor
ويتم استرداده بواسطة الاستعلام، وتعيين هذا الكائن ليكون المحوّل
ListView
Kotlin
// Defines a list of columns to retrieve from the Cursor and load into an output row val wordListColumns : Array<String> = arrayOf( UserDictionary.Words.WORD, // Contract class constant containing the word column name UserDictionary.Words.LOCALE // Contract class constant containing the locale column name ) // Defines a list of View IDs that receive the Cursor columns for each row val wordListItems = intArrayOf(R.id.dictWord, R.id.locale) // Creates a new SimpleCursorAdapter cursorAdapter = SimpleCursorAdapter( applicationContext, // The application's Context object R.layout.wordlistrow, // A layout in XML for one row in the ListView mCursor, // The result from the query wordListColumns, // A string array of column names in the cursor wordListItems, // An integer array of view IDs in the row layout 0 // Flags (usually none are needed) ) // Sets the adapter for the ListView wordList.setAdapter(cursorAdapter)
Java
// Defines a list of columns to retrieve from the Cursor and load into an output row String[] wordListColumns = { UserDictionary.Words.WORD, // Contract class constant containing the word column name UserDictionary.Words.LOCALE // Contract class constant containing the locale column name }; // Defines a list of View IDs that receive the Cursor columns for each row int[] wordListItems = { R.id.dictWord, R.id.locale}; // Creates a new SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter( getApplicationContext(), // The application's Context object R.layout.wordlistrow, // A layout in XML for one row in the ListView mCursor, // The result from the query wordListColumns, // A string array of column names in the cursor wordListItems, // An integer array of view IDs in the row layout 0); // Flags (usually none are needed) // Sets the adapter for the ListView wordList.setAdapter(cursorAdapter);
ملاحظة: للاحتفاظ بنسخة احتياطية من ListView
باستخدام
Cursor
، يجب أن يحتوي المؤشر على عمود باسم _ID
.
ولهذا السبب، يسترد طلب البحث المعروض سابقًا عمود _ID
جدول Words
، على الرغم من أنّ ListView
لا يعرضه.
تشرح هذه القيود أيضًا سبب تضمين معظم مقدّمي الخدمة عمود "_ID
" لكل من
جداولهم.
الحصول على بيانات من نتائج الاستعلام
بالإضافة إلى عرض نتائج طلبات البحث، يمكنك استخدامها في مهام أخرى. بالنسبة
على سبيل المثال، يمكنك استرداد التصحيحات الإملائية من مزود قاموس المستخدم ثم البحث عنها في
مزودي خدمة آخرين. ولإجراء ذلك، عليك التكرار خلال الصفوف في Cursor
، كما هو موضّح في المثال التالي:
Kotlin
/* * Only executes if the cursor is valid. The User Dictionary Provider returns null if * an internal error occurs. Other providers might throw an Exception instead of returning null. */ mCursor?.apply { // Determine the column index of the column named "word" val index: Int = getColumnIndex(UserDictionary.Words.WORD) /* * Moves to the next row in the cursor. Before the first movement in the cursor, the * "row pointer" is -1, and if you try to retrieve data at that position you get an * exception. */ while (moveToNext()) { // Gets the value from the column newWord = getString(index) // Insert code here to process the retrieved word ... // End of while loop } }
Java
// Determine the column index of the column named "word" int index = mCursor.getColumnIndex(UserDictionary.Words.WORD); /* * Only executes if the cursor is valid. The User Dictionary Provider returns null if * an internal error occurs. Other providers might throw an Exception instead of returning null. */ if (mCursor != null) { /* * Moves to the next row in the cursor. Before the first movement in the cursor, the * "row pointer" is -1, and if you try to retrieve data at that position you get an * exception. */ while (mCursor.moveToNext()) { // Gets the value from the column newWord = mCursor.getString(index); // Insert code here to process the retrieved word ... // End of while loop } } else { // Insert code here to report an error if the cursor is null or the provider threw an exception }
Cursor
عملية تنفيذ تحتوي على العديد من قيم "get" طرق
لاسترداد أنواع مختلفة من البيانات من الكائن. على سبيل المثال، قد يستخدم المقتطف السابق
تستخدم getString()
. تحتوي الغرف أيضًا على
getType()
التي تُرجع قيمة تشير إلى
نوع بيانات العمود.
إصدار موارد نتائج طلبات البحث
يجب أن يكون Cursor
عنصرًا
مغلق إذا لم تعد هناك حاجة إليها، حتى يتم تحرير الموارد المرتبطة بها
قريبًا. يمكن إجراء ذلك إما عن طريق استدعاء
close()
، أو باستخدام
عبارة try-with-resources
بلغة البرمجة Java أو
تعمل use()
في لغة البرمجة Kotlin.
أذونات موفّر المحتوى
يمكن لتطبيق الموفِّر تحديد الأذونات التي يجب أن تتطلّبها التطبيقات الأخرى الوصول إلى بيانات المزود. تتيح هذه الأذونات للمستخدم معرفة أنواع البيانات يحاول تطبيق الوصول إليه. بناءً على متطلبات مقدم الخدمة، قد تتضمن التطبيقات الأخرى يطلب الأذونات التي يحتاجون إليها للوصول إلى الموفر. يمكن للمستخدمين النهائيين الاطّلاع على الأذونات عند تثبيت التطبيق.
إذا لم يحدِّد تطبيق أحد الموفِّرين أي أذونات، حينئذٍ لن تتضمّن التطبيقات الأخرى إمكانية الوصول إلى بيانات الموفر، ما لم يتم تصدير موفر الخدمة. بالإضافة إلى ذلك، المكونات في تطبيق الموفر، يتمتع دائمًا بحق الدخول الكامل للقراءة والكتابة، بغض النظر عن الأذونات المحددة.
يتطلب مزود قاموس المستخدم
إذن "android.permission.READ_USER_DICTIONARY
" لاسترداد البيانات منه.
يملك مقدّم الخدمة android.permission.WRITE_USER_DICTIONARY
منفصل.
إذن لإدراج البيانات أو تحديثها أو حذفها.
للحصول على الأذونات اللازمة للوصول إلى أحد الموفّرين، يطلبها أحد التطبيقات من خلال
<uses-permission>
في ملف البيان الخاص به. وعندما يثبّت مدير حزم Android التطبيق،
يجب أن يوافق على جميع الأذونات التي يطلبها التطبيق. إذا وافق عليها المستخدم،
يواصل "مدير الحزم" عملية التثبيت. إذا لم يوافق المستخدم عليها، يجب على مدير الحزم
يؤدي إلى إيقاف التثبيت.
النموذج التالي
<uses-permission>
يطلب العنصر إذن الوصول للقراءة إلى موفّر قاموس المستخدم:
<uses-permission android:name="android.permission.READ_USER_DICTIONARY">
يمكن شرح تأثير الأذونات في وصول موفّر الخدمة بمزيد من التفصيل في نصائح الأمان:
إدراج البيانات وتحديثها وحذفها
بالطريقة نفسها التي تسترد بها البيانات من أحد المزودين، يمكنك أيضًا استخدام التفاعل بين
برنامج موفّر الخدمة وContentProvider
الخاص بالموفِّر لتعديل البيانات.
يمكنك استدعاء طريقة ContentResolver
مع الوسيطات التي تم تمريرها إلى
الطريقة المطابقة لـ ContentProvider
. مقدّم الخدمة ومقدّم الخدمة
مع الأمان والاتصال البيني للعمليات تلقائيًا.
إدخال البيانات
لإدراج بيانات في أحد المزودين، يمكنك الاتصال
ContentResolver.insert()
. تُدرج هذه الطريقة صفًا جديدًا في الموفر وتعرض معرف موارد منتظم (URI) للمحتوى لهذا الصف.
يوضح المقتطف التالي كيفية إدراج كلمة جديدة في موفِّر قاموس المستخدم:
Kotlin
// Defines a new Uri object that receives the result of the insertion lateinit var newUri: Uri ... // Defines an object to contain the new values to insert val newValues = ContentValues().apply { /* * Sets the values of each column and inserts the word. The arguments to the "put" * method are "column name" and "value". */ put(UserDictionary.Words.APP_ID, "example.user") put(UserDictionary.Words.LOCALE, "en_US") put(UserDictionary.Words.WORD, "insert") put(UserDictionary.Words.FREQUENCY, "100") } newUri = contentResolver.insert( UserDictionary.Words.CONTENT_URI, // The UserDictionary content URI newValues // The values to insert )
Java
// Defines a new Uri object that receives the result of the insertion Uri newUri; ... // Defines an object to contain the new values to insert ContentValues newValues = new ContentValues(); /* * Sets the values of each column and inserts the word. The arguments to the "put" * method are "column name" and "value". */ newValues.put(UserDictionary.Words.APP_ID, "example.user"); newValues.put(UserDictionary.Words.LOCALE, "en_US"); newValues.put(UserDictionary.Words.WORD, "insert"); newValues.put(UserDictionary.Words.FREQUENCY, "100"); newUri = getContentResolver().insert( UserDictionary.Words.CONTENT_URI, // The UserDictionary content URI newValues // The values to insert );
وتنتقل بيانات الصف الجديد إلى عنصر ContentValues
واحد، وهو
يتشابه شكله مع مؤشر من صف واحد. لا تحتاج الأعمدة في هذا الكائن إلى
نفس نوع البيانات، وإذا كنت لا تريد تحديد قيمة على الإطلاق، يمكنك تعيين عمود
إلى null
باستخدام ContentValues.putNull()
.
لا يضيف المقتطف السابق عمود "_ID
"، لأنّه يتم الاحتفاظ بهذا العمود.
تلقائيًا. يعيّن الموفِّر قيمة فريدة _ID
لكل صف
تمت إضافتها. يستخدم موفّرو الخدمات عادةً هذه القيمة كمفتاح أساسي للجدول.
يحدّد معرِّف الموارد المنتظم (URI) للمحتوى المعروض في newUri
الصف المضاف حديثًا باستخدام
بالتنسيق التالي:
content://user_dictionary/words/<id_value>
تمثّل القيمة <id_value>
محتوى _ID
في الصف الجديد.
ويمكن لمعظم موفّري المحتوى اكتشاف هذا النموذج من معرّف الموارد المنتظم (URI) للمحتوى تلقائيًا، ثم تنفيذ الإجراء المطلوب
العملية على هذا الصف بالتحديد.
للحصول على قيمة _ID
من Uri
الذي تم إرجاعه، اتصل
ContentUris.parseId()
تحديث البيانات
لتعديل صف، يمكنك استخدام عنصر ContentValues
مع البيانات المعدّلة.
كما تفعل مع معايير الإدراج والاختيار، تمامًا كما تفعل مع الاستعلام.
طريقة العميل التي تستخدمها هي
ContentResolver.update()
ما عليك سوى إضافة
إلى الكائن ContentValues
للأعمدة التي تعمل على تعديلها. إذا كنت
محو محتوى عمود، اضبط القيمة على null
.
يغير المقتطف التالي جميع الصفوف التي تحتوي لغتها على اللغة "en"
إلى
باللغة null
. والقيمة الناتجة هي عدد الصفوف التي تم تحديثها.
Kotlin
// Defines an object to contain the updated values val updateValues = ContentValues().apply { /* * Sets the updated value and updates the selected words. */ putNull(UserDictionary.Words.LOCALE) } // Defines selection criteria for the rows you want to update val selectionClause: String = UserDictionary.Words.LOCALE + "LIKE ?" val selectionArgs: Array<String> = arrayOf("en_%") // Defines a variable to contain the number of updated rows var rowsUpdated: Int = 0 ... rowsUpdated = contentResolver.update( UserDictionary.Words.CONTENT_URI, // The UserDictionary content URI updateValues, // The columns to update selectionClause, // The column to select on selectionArgs // The value to compare to )
Java
// Defines an object to contain the updated values ContentValues updateValues = new ContentValues(); // Defines selection criteria for the rows you want to update String selectionClause = UserDictionary.Words.LOCALE + " LIKE ?"; String[] selectionArgs = {"en_%"}; // Defines a variable to contain the number of updated rows int rowsUpdated = 0; ... /* * Sets the updated value and updates the selected words. */ updateValues.putNull(UserDictionary.Words.LOCALE); rowsUpdated = getContentResolver().update( UserDictionary.Words.CONTENT_URI, // The UserDictionary content URI updateValues, // The columns to update selectionClause, // The column to select on selectionArgs // The value to compare to );
تنظيف البيانات التي أدخلها المستخدم عند الاتصال
ContentResolver.update()
لمزيد من المعلومات حول
هذا، اقرأ قسم الحماية من الإدخالات الضارة.
حذف البيانات
يشبه حذف الصفوف استرداد بيانات الصفوف. يمكنك تحديد معايير الاختيار للصفوف
تريد حذفه، وتُرجع طريقة العميل عدد الصفوف المحذوفة.
يحذف المقتطف التالي الصفوف التي يتطابق رقم تعريف تطبيقها مع "user"
. تُرجع الطريقة دالة
عدد الصفوف المحذوفة.
Kotlin
// Defines selection criteria for the rows you want to delete val selectionClause = "${UserDictionary.Words.APP_ID} LIKE ?" val selectionArgs: Array<String> = arrayOf("user") // Defines a variable to contain the number of rows deleted var rowsDeleted: Int = 0 ... // Deletes the words that match the selection criteria rowsDeleted = contentResolver.delete( UserDictionary.Words.CONTENT_URI, // The UserDictionary content URI selectionClause, // The column to select on selectionArgs // The value to compare to )
Java
// Defines selection criteria for the rows you want to delete String selectionClause = UserDictionary.Words.APP_ID + " LIKE ?"; String[] selectionArgs = {"user"}; // Defines a variable to contain the number of rows deleted int rowsDeleted = 0; ... // Deletes the words that match the selection criteria rowsDeleted = getContentResolver().delete( UserDictionary.Words.CONTENT_URI, // The UserDictionary content URI selectionClause, // The column to select on selectionArgs // The value to compare to );
تنظيف البيانات التي أدخلها المستخدم عند الاتصال
ContentResolver.delete()
لمزيد من المعلومات حول
هذا، اقرأ قسم الحماية من الإدخالات الضارة.
أنواع بيانات موفّري المحتوى
يمكن لمزودي المحتوى توفير العديد من أنواع البيانات المختلفة. يقدم مزود قاموس المستخدم فقط ولكن يمكن لمزوّدي الخدمات أيضًا تقديم التنسيقات التالية:
- عدد صحيح
- عدد صحيح طويل (طويل)
- النقطة العائمة
- نقطة عائمة طويلة (مزدوجة)
هناك نوع بيانات آخر يستخدمه الموفرون غالبًا وهو كائن ثنائي كبير (BLOB) يتم تنفيذه باعتباره
مصفوفة بايت بحجم 64 كيلوبايت يمكنك الاطّلاع على أنواع البيانات المتاحة من خلال مراجعة
صف واحد (Cursor
) "get" الطرق.
عادةً ما يتم سرد نوع البيانات لكل عمود في الموفر في وثائقه.
تكون أنواع البيانات لمزود قاموس المستخدم مدرجة في الوثائق المرجعية
لفئة العقد، UserDictionary.Words
. فئات العقود هي
كما هو موضح في قسم فئات العقود.
يمكنك أيضًا تحديد نوع البيانات من خلال طلب الرقم Cursor.getType()
.
ويحتفظ الموفّرون أيضًا بمعلومات نوع بيانات MIME لكل معرّف موارد منتظم (URI) للمحتوى يتم تحديده. يمكنك معلومات نوع MIME لمعرفة ما إذا كان تطبيقك يمكنه معالجة البيانات التي أو اختيار نوع المعالجة بناءً على نوع MIME. تحتاج عادةً إلى تستخدم نوع MIME عند العمل مع مقدّم خدمة يحتوي على عناصر معقدة وهياكل أو ملفات البيانات.
على سبيل المثال، ContactsContract.Data
في "مقدِّم جهات الاتصال" أنواع MIME لتسمية نوع بيانات جهة الاتصال المخزنة في كل
الصف. للحصول على نوع MIME المتوافق مع معرّف الموارد المنتظم (URI) للمحتوى، اتصل
ContentResolver.getType()
يصف قسم مرجع نوع MIME لكل من أنواع MIME العادية والمخصَّصة.
الطرق البديلة لوصول مقدّمي الخدمات
هناك ثلاثة أشكال بديلة لوصول مزوِّدي الخدمات اللازمة في تطوير التطبيقات:
-
الوصول المجمّع: يمكنك إنشاء دُفعة من طلبات الوصول بالطرق ضمن
فئة
ContentProviderOperation
ثم تطبيقهاContentResolver.applyBatch()
-
الاستعلامات غير المتزامنة: إجراء طلبات البحث في سلسلة محادثات منفصلة. يمكنك
استخدِم كائن
CursorLoader
. ينبغي أن تتضمن الأمثلة في توضيح دليل التحميلات كيفية القيام بذلك. - الوصول إلى البيانات باستخدام عناصر intent: على الرغم من أنّه لا يمكنك إرسال هدف. مباشرةً إلى أحد الموفّرين، يمكنك إرسال هدف إلى تطبيق المزود، وهو وهو عادةً أفضل تجهيزًا لتعديل بيانات المزود.
يتم توضيح إمكانية الوصول المجمّع والتعديل باستخدام الأهداف في الأقسام التالية.
الوصول المجمّع
يُعد الوصول المجمّع إلى أحد الموفّرين مفيدًا لإدراج عدد كبير من الصفوف لإدراجها صفوف في جداول متعددة بنفس استدعاء الطريقة، وبشكل عام لتنفيذ مجموعة من العمليات التي تتم عبر حدود العملية كمعاملة، تُسمى العملية البسيطة.
وللوصول إلى أحد الموفّرين في الوضع المجمَّع،
إنشاء مصفوفة من عناصر ContentProviderOperation
ثم
وإرسالها إلى موفّر المحتوى
ContentResolver.applyBatch()
يمكنك اجتياز
سلطة موفّر المحتوى لهذه الطريقة، بدلاً من معرّف موارد منتظم (URI) معين للمحتوى.
يتيح ذلك لكل عنصر ContentProviderOperation
في المصفوفة العمل.
مقابل جدول مختلف. يؤدي استدعاء ContentResolver.applyBatch()
إلى عرض مصفوفة من النتائج.
وصف فئة العقد ContactsContract.RawContacts
يتضمن مقتطف رمز يوضح الإدراج المجمّع.
الوصول إلى البيانات باستخدام عناصر intent
يمكن أن توفر الأهداف وصولاً غير مباشر لموفّر المحتوى. يمكنك السماح للمستخدم بالوصول إلى البيانات لدى أحد المزودين حتى إذا لم يكن لدى التطبيق أذونات الوصول إلى البيانات من خلال الحصول على نتيجة intent من تطبيق لديه أذونات أو من خلال تفعيل تطبيق لديه أذونات ويسمح للمستخدم بالعمل فيه.
الحصول على أذونات وصول مؤقتة
يمكنك الوصول إلى البيانات لدى أحد موفّري المحتوى، حتى إذا لم يكن لديك صلاحيات الوصول المناسبة الأذونات، عن طريق إرسال هدف إلى تطبيق لديه الأذونات تلقي هدف نتيجة تحتوي على أذونات معرف الموارد المنتظم (URI). هذه أذونات لعنوان URI محدد للمحتوى تستمر حتى النشاط الذي يتلقى الانتهاء منها. التطبيق الذي يحتوي على أذونات دائمة يمنح أذونات مؤقتة الأذونات من خلال وضع علامة في الغرض من النتيجة:
-
إذن القراءة:
FLAG_GRANT_READ_URI_PERMISSION
-
إذن الكتابة:
FLAG_GRANT_WRITE_URI_PERMISSION
ملاحظة: لا تمنح هذه العلامات إذنًا عامًا لمقدِّم الخدمة بالقراءة أو الكتابة. الذي يتم تضمين سلطته في معرف الموارد المنتظم (URI) للمحتوى. لا يتوفر الوصول إلا لعنوان URI نفسه.
عند إرسال معرّفات الموارد المنتظمة (URI) للمحتوى إلى تطبيق آخر، عليك تضمين واحد على الأقل من هذه المعرّفات. الأعلام. توفِّر العلامات الإمكانات التالية لأي تطبيق يتلقّى هدف وتستهدف الإصدار 11 من نظام التشغيل Android (المستوى 30) أو الإصدارات الأحدث:
- اقرأ من البيانات التي يمثلها معرف الموارد المنتظم (URI) للمحتوى أو اكتب إليها، اعتمادًا على العلامة المضمَّنة في الهدف.
- الحصول على حزمة إذن الوصول إلى التطبيق الذي يتضمّن موفِّر المحتوى الذي يتطابق مع مرجع معرّف الموارد المنتظم (URI). التطبيق الذي يرسل الغرض والتطبيق الذي يتضمن موفر المحتوى تطبيقين مختلفين.
يحدد الموفر أذونات عنوان URI لمعرّفات الموارد المنتظمة (URI) للمحتوى في ملف البيان الخاص به، وذلك باستخدام
android:grantUriPermissions
سمة
<provider>
العنصر بالإضافة إلى
<grant-uri-permission>
العنصر الثانوي
<provider>
العنصر. يتم شرح آلية أذونات عنوان URI بمزيد من التفصيل في
دليل الأذونات على Android.
على سبيل المثال، يمكنك استرداد البيانات لجهة اتصال في "مقدم جهات الاتصال"، حتى إذا لم
يكون لديك إذن READ_CONTACTS
. قد ترغب في القيام
هذا في تطبيق يرسل التحية الإلكترونية إلى جهة اتصال في عيد ميلادها. بدلاً من
تطلب READ_CONTACTS
، التي تتيح لك الوصول إلى جميع
جهات اتصال المستخدم وجميع معلوماته، وتتيح للمستخدم التحكم في
جهات الاتصال التي يستخدمها تطبيقك. لإجراء ذلك، يُرجى اتّباع العملية التالية:
-
أرسِل في تطبيقك هدفًا يحتوي على الإجراء.
ACTION_PICK
و"جهات الاتصال" نوع MIMECONTENT_ITEM_TYPE
، باستخدام الطريقةstartActivityForResult()
. - ولأن هذا الهدف يتطابق مع فلتر الأهداف "اختيار" تطبيق الأشخاص النشاط، يظهر النشاط في المقدمة.
-
في نشاط التحديد، يختار المستخدم
جهة اتصال للتحديث. عند حدوث ذلك، يستدعي نشاط التحديد
setResult(resultcode, intent)
لإعداد نية لرد الجميل إلى تطبيقك. يتضمن الغرض معرّف الموارد المنتظم (URI) للمحتوى جهة الاتصال التي اختارها المستخدم و"الإضافات" العلامةFLAG_GRANT_READ_URI_PERMISSION
تمنح هذه العلامات عنوان URI إذنًا لتطبيقك لقراءة بيانات جهة الاتصال التي أشار إليها معرف الموارد المنتظم (URI) للمحتوى. بعد ذلك، يتّصل نشاط الاختيار بـ "finish()
" إلى إرجاع التحكم إلى تطبيقك. -
يعود نشاطك إلى المقدّمة ويتصل النظام
onActivityResult()
. تتلقى هذه الطريقة الغرض من النتيجة التي تم إنشاؤها بواسطة نشاط التحديد في تطبيق الأشخاص. - باستخدام معرّف الموارد المنتظم (URI) للمحتوى من الغرض من النتيجة، يمكنك قراءة بيانات جهة الاتصال من "مقدِّم جهات الاتصال"، على الرغم من أنّك لم تطلب إذن الوصول الدائم للقراءة إلى الموفِّر في بيان التطبيق يمكنك بعد ذلك الحصول على معلومات تاريخ ميلاد جهة الاتصال أو عنوان بريد إلكتروني ثم أرسل التحية الإلكترونية.
استخدام تطبيق آخر
يمكنك أيضًا السماح للمستخدم بتعديل البيانات التي لا تملك أذونات وصول إليها، وهي تنشيط تطبيق لديه أذونات والسماح للمستخدم بتنفيذ العمل هناك.
على سبيل المثال، يقبل تطبيق التقويم
ACTION_INSERT
هدفًا يتيح لك تفعيل
واجهة مستخدم الإدراج للتطبيق. يمكنك ضبط "ميزات إضافية" البيانات بهذا الغرض، والتي قد يفكر فيها التطبيق
لملء واجهة المستخدم مسبقًا. نظرًا لاحتواء الأحداث المتكررة على بنية معقدة،
لإدراج الأحداث في "موفر التقويم" هي تنشيط تطبيق التقويم
ACTION_INSERT
، ثم السماح للمستخدم بإدراج الحدث هناك.
عرض البيانات باستخدام تطبيق مساعد
إذا كان تطبيقك لديه أذونات وصول، قد تستمر في استخدام
نية عرض البيانات في تطبيق آخر. على سبيل المثال، يقبل تطبيق التقويم
ACTION_VIEW
intent يعرض تاريخًا أو حدثًا معيّنًا.
يُتيح لك ذلك عرض معلومات التقويم بدون الحاجة إلى إنشاء واجهة مستخدم خاصة بك.
لمزيد من المعلومات عن هذه الميزة، يُرجى مراجعة
نظرة عامة على موفّر "تقويم Google".
لا يجب أن يكون التطبيق الذي ترسل إليه intent هو التطبيق.
المرتبط بمقدّم الخدمة. على سبيل المثال، يمكنك استرداد جهة اتصال من
التواصل مع مقدّم الخدمة، ثم إرسال هدف واحد (ACTION_VIEW
)
يتضمن معرف الموارد المنتظم (URI) للمحتوى الخاص بصورة جهة الاتصال إلى عارض الصور.
فئات العقود
تحدد فئة العقد الثوابت التي تساعد التطبيقات على العمل مع معرفات الموارد المنتظمة (URI) للمحتوى، عمود
والأسماء والإجراءات المقصودة والميزات الأخرى الخاصة بموفّر المحتوى. فئات العقود ليست
يتم تضمينه تلقائيًا مع مزود الخدمة. يتعين على مطور الموفر تحديدها ثم
وإتاحتها للمطورين الآخرين. والعديد من مزوّدي نظام التشغيل Android
لمنصة العرض فئات تعاقد مقابلة في الحزمة android.provider
.
على سبيل المثال، لدى موفِّر قاموس المستخدم فئة عقد
UserDictionary
يتضمّن معرّف الموارد المنتظم (URI) للمحتوى وثابت اسم العمود. تشير رسالة الأشكال البيانية
يتم تحديد معرّف الموارد المنتظم (URI) للمحتوى في جدول Words
في القيمة الثابتة.
UserDictionary.Words.CONTENT_URI
تحتوي الفئة UserDictionary.Words
أيضًا على ثوابت أسماء الأعمدة،
والمستخدَمة في أمثلة المقتطفات في هذا الدليل على سبيل المثال، يمكن التنبؤ باستعلام البحث
على النحو التالي:
Kotlin
val projection : Array<String> = arrayOf( UserDictionary.Words._ID, UserDictionary.Words.WORD, UserDictionary.Words.LOCALE )
Java
String[] projection = { UserDictionary.Words._ID, UserDictionary.Words.WORD, UserDictionary.Words.LOCALE };
فئة عقد أخرى هي ContactsContract
لمقدّم جهات الاتصال.
تتضمن المستندات المرجعية لهذا الصف أمثلة على مقتطفات الرموز. أحد هذه العناصر
الفئات الفرعية، ContactsContract.Intents.Insert
، عبارة عن عقد
فئة تحتوي على ثوابت لبيانات الأهداف والنوايا.
مرجع نوع MIME
ويمكن لموفّري المحتوى عرض أنواع وسائط MIME عادية أو سلاسل مخصّصة من نوع MIME أو كلتيهما.
تكون أنواع MIME بالتنسيق التالي:
type/subtype
على سبيل المثال، إنّ نوع MIME المعروف text/html
له النوع text
النوع الفرعي html
. إذا عرض الموفر هذا النوع لعنوان URI، فهذا يعني أن
يستخدم عنوان URI هذا نصًا يحتوي على علامات HTML.
تحتوي سلاسل من نوع MIME المخصصة، وتسمى أيضًا أنواع MIME الخاصة بالمورّد، على المزيد قيم type وsubtype معقدة. بالنسبة إلى الصفوف المتعددة، تكون قيمة النوع دائمًا كما يلي:
vnd.android.cursor.dir
بالنسبة إلى صف واحد، تكون قيمة النوع دائمًا كما يلي:
vnd.android.cursor.item
إنّ subtype خاص بموفِّر الخدمة. عادةً ما يكون لدى مزودي خدمة Android المضمّنين النوع الفرعي. فعلى سبيل المثال، عندما ينشئ تطبيق جهات الاتصال صفًا لرقم هاتف، يضبط نوع MIME التالي في الصف:
vnd.android.cursor.item/phone_v2
قيمة النوع الفرعي هي phone_v2
.
يمكن لمطوّري البرامج الآخرين إنشاء نمط من الأنواع الفرعية الخاصة بهم استنادًا إلى أنواع
أسماء السلطة والجداول. على سبيل المثال، إليك مقدّم خدمة يوفّر جداول مواعيد للقطارات.
إنّ مرجع موفر الخدمة هو com.example.trains
، ويحتوي على الجداول
السطر1 والسطر2 والسطر 3. ردًا على معرف الموارد المنتظم (URI) للمحتوى التالي للجدول Line1:
content://com.example.trains/Line1
يعرض الموفِّر نوع MIME التالي:
vnd.android.cursor.dir/vnd.example.line1
ردًا على معرف الموارد المنتظم (URI) للمحتوى التالي للصف 5 في الجدول السطر2:
content://com.example.trains/Line2/5
يعرض الموفِّر نوع MIME التالي:
vnd.android.cursor.item/vnd.example.line2
يحدد معظم موفّري المحتوى ثوابت فئة العقد لأنواع MIME التي يستخدمونها. تشير رسالة الأشكال البيانية
فئة عقد مزوّد جهات الاتصال ContactsContract.RawContacts
،
على سبيل المثال، يحدد الثابت
CONTENT_ITEM_TYPE
لنوع MIME
صف جهة اتصال أولي واحد.
يتم توضيح معرفات الموارد المنتظمة (URI) للمحتوى للصفوف الفردية في قسم معرّفات الموارد المنتظمة (URI) للمحتوى.