Content Provider: چیست، معماری کامپوننت و اصل کار

نویسنده: IT Sectr منتشر شده: 2026-06-17 زمان مطالعه: 8 دقیقه

Content Provider — کامپوننت Android است که یک رابط یکپارچه برای دسترسی به داده‌ها بین برنامه‌ها فراهم می‌کند. این کامپوننت ذخیره‌سازی فیزیکی (SQLite، فایل‌ها، منابع شبکه) را انتزاع می‌کند و تبادل امن اطلاعات را از طریق ContentResolver تضمین می‌کند. بر اساس Android Developer Guide, 2026، Content Provider یکی از چهار کامپوننت اصلی برنامه Android همراه با Activity، Service و BroadcastReceiver است. وظیفه آن — در دسترس قرار دادن داده‌ها برای سایر برنامه‌ها با کنترل مجوزهای خواندن و نوشتن است.

نکات اصلی

  • Content Provider — کامپوننت استاندارد Android برای تبادل داده بین برنامه‌ها از طریق رابط ContentResolver.
  • URI (content://) جدول یا رکورد را شناسایی می‌کند و برای تمام عملیات CRUD با ارائه‌دهنده استفاده می‌شود.
  • UriMatcher — کلاس کمکی که URIهای ورودی را تجزیه می‌کند و تعیین می‌کند کدام جدول یا سطر درخواست شده است.
  • مجوزها خواندن و نوشتن در مانیفست تنظیم می‌شوند و هنگام نصب از کاربر درخواست می‌شوند.
  • CursorLoader یا Room با Content Provider بارگذاری ناهمزمان داده‌ها از ارائه‌دهنده را بدون مسدود کردن رشته UI تضمین می‌کنند.

Content Provider چیست؟

Content Provider — کامپوننت Android است که دسترسی به مخزن داده متمرکز را مدیریت می‌کند و آنها را از طریق یک رابط قراردادی یکپارچه در اختیار سایر برنامه‌ها قرار می‌دهد. این کامپوننت جزئیات پیاده‌سازی ذخیره‌سازی را پنهان می‌کند: داده‌ها می‌توانند در SQLite، سیستم فایل، ابر یا نتیجه یک درخواست شبکه باشند.

Android شامل Content Providerهای داخلی برای داده‌های سیستمی است — ContactsContract، MediaStore، CalendarContract، CallLog. برنامه‌های شخص ثالث نیز می‌توانند ارائه‌دهندگان خود را برای تبادل امن داده‌ها ایجاد کنند. هر ارائه‌دهنده در AndroidManifest.xml با مشخص کردن authority — یک رشته یکتا که بخش اول URI را تشکیل می‌دهد — ثبت می‌شود.

Content Provider چگونه کار می‌کند

Content Provider بر اساس مدل مشتری-سرور کار می‌کند. ارائه‌دهنده به عنوان سروری عمل می‌کند که شش روش اجباری را پیاده‌سازی می‌کند: query، insert، update، delete، getType و onCreate. مشتری (برنامه دیگر) از طریق ContentResolver به ارائه‌دهنده دسترسی پیدا می‌کند که فراخوانی‌ها را از طریق مکانیزم IPC Android به روش‌های مربوطه ارائه‌دهنده منتقل می‌کند.

URI و authority

هر Content Provider با URI طرح content:// شناسایی می‌شود. به عنوان مثال، content://com.example.app.provider/items. بخش اول authority (com.example.app.provider) به کلاس ارائه‌دهنده در مانیفست متصل می‌شود. مسیر /items به جدول و /items/5 به رکورد خاص با ID=5 اشاره می‌کند.

فرآیند فراخوانی

هنگامی که یک برنامه ContentResolver.query(URI) را فراخوانی می‌کند، Android مجوزهای بسته فراخواننده را بررسی می‌کند، ارائه‌دهنده را با authority پیدا می‌کند و اگر هنوز راه‌اندازی نشده باشد، فرآیند آن را شروع می‌کند. ارائه‌دهنده درخواست را اجرا می‌کند و Cursor — شیئی که حاوی نتیجه است و به مشتری امکان پیمایش روی رکوردها را می‌دهد — برمی‌گرداند.

روش‌های اصلی Content Provider

کلاس ContentProvider نیاز به پیاده‌سازی شش روش انتزاعی دارد. هر روش URI را دریافت می‌کند و نتیجه متناسب با نوع عملیات را برمی‌گرداند. سیستم این روش‌ها را از هر فرآیندی فراخوانی می‌کند، بنابراین آنها باید thread-safe باشند و اجرا را برای مدت طولانی مسدود نکنند.

روش query

روش query URI، آرایه ستون‌های projection، رشته selection با آرگومان‌ها و ترتیب مرتب‌سازی را دریافت می‌کند. یک Cursor با داده‌ها برمی‌گرداند. در پیاده‌سازی باید URI را با UriMatcher تجزیه کرد و درخواست SQL مربوطه را به پایگاه داده اجرا کرد.

روش‌های insert، update، delete

این روش‌ها داده‌ها را در مخزن تغییر می‌دهند. insert ContentValues — جفت‌های کلید-مقدار را دریافت می‌کند و URI رکورد جدید را برمی‌گرداند. update و delete selection را برای فیلتر کردن رکوردها دریافت می‌کنند و تعداد سطرهای تحت تأثیر را برمی‌گردانند. پس از تغییر داده‌ها، ارائه‌دهنده باید از طریق ContentResolver.notifyChange اطلاع دهد.

روشهدفبازگشت
queryدریافت داده‌ها با URICursor یا null
insertافزودن رکورد جدیدURI رکورد جدید
updateبه‌روزرسانی رکوردهای موجودint (تعداد سطرها)
deleteحذف رکوردهاint (تعداد سطرها)
getTypeنوع MIME برای URIString
onCreateراه‌اندازی ارائه‌دهندهboolean

ContentResolver و URI در Android

ContentResolver — یک نقطه دسترسی واحد برای کار با تمام Content Providerها در سیستم است. برنامه مشتری هرگز روش‌های ارائه‌دهنده را مستقیماً فراخوانی نمی‌کند — فقط از طریق ContentResolver که Android از context دریافت می‌کند. عملیات CRUD در ContentResolver همان نام‌های ارائه‌دهنده را دارند اما به جای ارجاع مستقیم، URI دریافت می‌کنند.

UriMatcher

برای تجزیه URIهای ورودی در داخل ارائه‌دهنده از UriMatcher استفاده می‌شود. این امکان را می‌دهد که URI با یک کد عددی مطابقت داده شود — به عنوان مثال، URI content://authority/items کد 1 و content://authority/items/# کد 2 را می‌دهد. این کار نیاز به تجزیه دستی رشته URI در هر روش را از بین می‌برد.

kotlin
// استفاده از ContentResolver برای دسترسی به مخاطبین
val uri = ContactsContract.Contacts.CONTENT_URI
val cursor = contentResolver.query(
    uri,
    arrayOf(ContactsContract.Contacts.DISPLAY_NAME),
    null, null, null
)
cursor?.use {
    while (it.moveToNext()) {
        val name = it.getString(it.getColumnIndexOrThrow(
            ContactsContract.Contacts.DISPLAY_NAME
        ))
        Log.d("مخاطبین", "نام: $name")
    }
}

Cursor پس از استفاده باید حتماً بسته شود — در مثال بالا use (تابع توسعه‌ای Kotlin) این کار را انجام می‌دهد. اگر Cursor بسته نشود، نشت حافظه رخ می‌دهد زیرا مرجعی به داده‌ها در حافظه Binder نگه می‌دارد. برای سناریوهای UI از CursorLoader یا Room با LiveData/Flow استفاده کنید.

مثال Content Provider در Kotlin

ایجاد Content Provider شخصی خود با ارث‌بری از کلاس ContentProvider شروع می‌شود. ارائه‌دهنده با پایگاه داده SQLite از طریق SQLiteOpenHelper کار می‌کند و از UriMatcher برای تعیین نوع درخواست استفاده می‌کند. بیایید یک پیاده‌سازی حداقلی برای مدیریت لیست یادداشت‌ها را بررسی کنیم.

ثبت در مانیفست

ارائه‌دهنده در AndroidManifest.xml در داخل تگ application ثبت می‌شود. ویژگی authorities یک شناسه یکتا را تعیین می‌کند و exported مشخص می‌کند که آیا سایر برنامه‌ها می‌توانند به ارائه‌دهنده دسترسی داشته باشند. بدون exported=true ارائه‌دهنده فقط در داخل برنامه شما قابل دسترسی است.

kotlin
// مثال Content Provider برای یادداشت‌ها
class NotesProvider : ContentProvider() {

    companion object {
        const val AUTHORITY = "com.example.app.notes"
        const val NOTES_PATH = "notes"
        const val NOTES_URI = "content://$AUTHORITY/$NOTES_PATH"
        const val NOTES_ID = "content://$AUTHORITY/$NOTES_PATH/#"

        private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
            addURI(AUTHORITY, NOTES_PATH, 1)
            addURI(AUTHORITY, "$NOTES_PATH/#", 2)
        }
    }

    override fun query(uri: Uri, projection: Array<String>?,
        selection: String?, args: Array<String>?, sort: String?): Cursor? {
        return when (uriMatcher.match(uri)) {
            1 -> dbHelper.readableDatabase.query(TABLE_NOTES,
                projection, selection, args, null, null, sort)
            2 -> dbHelper.readableDatabase.query(TABLE_NOTES,
                projection, "_id=?", arrayOf(uri.lastPathSegment), null, null, null)
            else -> throw IllegalArgumentException("Unknown URI: $uri")
        }
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        val id = dbHelper.writableDatabase.insert(TABLE_NOTES, null, values)
        context?.contentResolver?.notifyChange(uri, null)
        return ContentUris.withAppendedId(uri, id)
    }

    override fun delete(uri: Uri, selection: String?, args: Array<String>?): Int {
        val count = dbHelper.writableDatabase.delete(TABLE_NOTES, selection, args)
        context?.contentResolver?.notifyChange(uri, null)
        return count
    }

    // getType, update, onCreate برای اختصار حذف شده است
}

پس از ایجاد کلاس، ارائه‌دهنده باید در مانیفست با ویژگی‌های android:authorities و android:exported (true اگر ارائه‌دهنده عمومی است) ثبت شود. سیستم نمونه ارائه‌دهنده را در اولین مراجعه به آن ایجاد می‌کند — این در رشته UI رخ می‌دهد، بنابراین onCreate باید سریع اجرا شود.

محافظت از داده‌ها از طریق مجوزها

Content Provider امکان مدیریت دسترسی به داده‌ها را در دو سطح فراهم می‌کند: مجوزهای خواندن و مجوزهای نوشتن. آنها در مانیفست با ویژگی‌های android:readPermission و android:writePermission تنظیم می‌شوند. اگر برنامه مشتری مجوز مربوطه را نداشته باشد، سیستم فراخوانی را با SecurityException رد می‌کند.

مجوز در سطح URI

Android از مجوزهای موقت از طریق پرچم‌های FLAG_GRANT_READ_URI_PERMISSION و FLAG_GRANT_WRITE_URI_PERMISSION پشتیبانی می‌کند. این زمانی مفید است که برنامه URI یک فایل را از طریق Intent به برنامه دیگری ارسال می‌کند — دریافت‌کننده فقط به URI خاص برای مدت محدود دسترسی پیدا می‌کند. سیستم مجوز موقت را پس از اتمام کار برنامه دریافت‌کننده لغو می‌کند.

برای ارائه‌دهندگان سیستمی، Android نیاز به مشخص کردن مجوزهای خاص در مانیفست برنامه دارد. به عنوان مثال، برای دسترسی به مخاطبین READ_CONTACTS، برای تقویم — READ_CALENDAR نیاز است. از Android 6، این مجوزها در زمان اجرا درخواست می‌شوند، نه هنگام نصب.

سوالات متداول

Content Provider در Android چیست؟

Content Provider — کامپوننت Android است که یک رابط استاندارد برای تبادل داده بین برنامه‌ها از طریق ContentResolver فراهم می‌کند. این کامپوننت روش ذخیره‌سازی (SQLite، فایل‌ها، شبکه) را انتزاع می‌کند و دسترسی امن به داده‌ها را با کنترل مجوزهای خواندن و نوشتن تضمین می‌کند.

Authority در Content Provider چیست؟

Authority — یک رشته شناسه یکتای ارائه‌دهنده است که در AndroidManifest.xml مشخص می‌شود. این رشته بخش اول URI content://authority/path را تشکیل می‌دهد و توسط سیستم برای مسیریابی فراخوانی‌های ContentResolver به ارائه‌دهنده مناسب استفاده می‌شود. Authority باید در بین تمام برنامه‌های روی دستگاه یکتا باشد.

UriMatcher در Content Provider چگونه کار می‌کند؟

UriMatcher URIها را با کدهای عددی مطابقت می‌دهد. شما الگوها را از طریق addURI اضافه می‌کنید، سپس match را برای دریافت کد URI ورودی فراخوانی می‌کنید. این امکان را در روش‌های query، insert، update، delete فراهم می‌کند تا تعیین کنید کدام جدول یا رکورد درخواست شده است و عملیات مربوطه را روی پایگاه داده اجرا کنید.

آیا باید Cursor را پس از کار با ContentResolver بست؟

بله، Cursor حتماً باید پس از استفاده بسته شود. اگر Cursor بسته نشود، نشت حافظه رخ می‌دهد زیرا مرجع Binder به داده‌های ارائه‌دهنده را نگه می‌دارد. در Kotlin از تابع use برای بستن خودکار و در Java از try-with-resources یا فراخوانی cursor.close() در finally استفاده کنید.

تفاوت Content Provider با SQLiteDatabase چیست؟

Content Provider — کامپوننتی برای دسترسی بین برنامه‌ای به داده‌ها است، در حالی که SQLiteDatabase مخزن داخلی یک برنامه است. Content Provider رابط URI و کنترل مجوز را فراهم می‌کند، در حالی که SQLiteDatabase مستقیماً با پایگاه داده بدون مکانیزم‌های امنیتی در سطح سیستم‌عامل کار می‌کند.

خلاصه

  • Content Provider — کامپوننت استاندارد Android برای تبادل امن داده بین برنامه‌ها از طریق رابط یکپارچه ContentResolver است.
  • URI طرح content://authority/path/id ارائه‌دهنده، جدول و رکورد خاص را شناسایی می‌کند — هر بخش هدف مشخصی دارد.
  • UriMatcher تجزیه URIهای ورودی در داخل ارائه‌دهنده را ساده می‌کند و نیاز به تجزیه دستی رشته‌ها در هر روش CRUD را از بین می‌برد.
  • ارائه‌دهنده در AndroidManifest.xml با ویژگی‌های authorities و exported ثبت می‌شود — این مکانیزم سیستمی است که بدون آن ارائه‌دهنده کار نمی‌کند.
  • ContentValues به عنوان مجموعه‌ای از جفت‌های کلید-مقدار به insert و update منتقل می‌شوند و Cursor از query برای پیمایش نتایج بازگردانده می‌شود.
  • مجوزهای readPermission و writePermission در مانیفست دسترسی به داده‌ها را کنترل می‌کنند و FLAG_GRANT_URI_PERMISSION دسترسی موقت به URI خاص را فراهم می‌کند.
  • برای بارگذاری ناهمزمان داده‌ها از Content Provider از CursorLoader، Room با ContentProvider یا LoaderManager استفاده کنید — این کار از مسدود شدن رشته UI جلوگیری می‌کند.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید