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 Providers ในตัวสำหรับข้อมูลระบบ — 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 และส่งคืนผลลัพธ์ที่สอดคล้องกับประเภทการดำเนินการ ระบบเรียกเมธอดเหล่านี้จากกระบวนการใดก็ได้ ดังนั้นจึงต้องปลอดภัยต่อเธรดและไม่บล็อกการทำงานเป็นเวลานาน

เมธอด 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 Providers ทั้งหมดในระบบ แอปพลิเคชันไคลเอนต์ไม่เคยเรียกเมธอดผู้ให้บริการโดยตรง — เฉพาะผ่าน ContentResolver ซึ่ง Android ได้รับจากบริบท การดำเนินการ 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 สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม