Android มีเฟรมเวิร์กที่ทรงพลังซึ่งอิงตามคลิปบอร์ดสำหรับการคัดลอกและวาง โดยรองรับประเภทข้อมูลอย่างง่าย และซับซ้อน รวมถึงสตริงข้อความ โครงสร้างข้อมูลที่ซับซ้อน ข้อมูลสตรีมข้อความและไบนารี และชิ้นงานของแอปพลิเคชัน ระบบจะจัดเก็บข้อมูลข้อความธรรมดาไว้ในคลิปบอร์ดโดยตรง ส่วนข้อมูลที่ซับซ้อน จะจัดเก็บเป็นข้อมูลอ้างอิงที่แอปพลิเคชันที่วางจะแก้ไขด้วยผู้ให้บริการเนื้อหา การคัดลอก และการวางจะทำงานทั้งภายในแอปพลิเคชันและระหว่างแอปพลิเคชันที่ใช้เฟรมเวิร์ก
เนื่องจากเฟรมเวิร์กบางส่วนใช้ผู้ให้บริการเนื้อหา เอกสารนี้จึงถือว่าคุณคุ้นเคยกับ Android Content Provider API ซึ่งอธิบายไว้ใน ผู้ให้บริการเนื้อหา
ผู้ใช้คาดหวังว่าจะได้รับความคิดเห็นเมื่อคัดลอกเนื้อหาไปยังคลิปบอร์ด ดังนั้นนอกเหนือจากเฟรมเวิร์กที่ขับเคลื่อนการคัดลอกและวางแล้ว Android ยังแสดง UI เริ่มต้นต่อผู้ใช้เมื่อคัดลอกใน Android 13 (API ระดับ 33) ขึ้นไป ฟีเจอร์นี้อาจทำให้เกิดความเสี่ยงที่จะมีการแจ้งเตือนซ้ำ ดูข้อมูลเพิ่มเติมเกี่ยวกับ กรณีข้อยกเว้นนี้ได้ในส่วน หลีกเลี่ยงการแจ้งเตือนที่ซ้ำกัน

แสดงความคิดเห็นต่อผู้ใช้ด้วยตนเองเมื่อคัดลอกใน Android 12L (API ระดับ 32) และต่ำกว่า ดูคำแนะนำสำหรับเรื่องนี้ในเอกสารนี้
เฟรมเวิร์กของคลิปบอร์ด
เมื่อใช้เฟรมเวิร์กคลิปบอร์ด ให้ใส่ข้อมูลลงในออบเจ็กต์คลิป แล้วใส่ออบเจ็กต์คลิปลงในคลิปบอร์ดทั่วทั้งระบบ ออบเจ็กต์คลิปอาจอยู่ในรูปแบบใดรูปแบบหนึ่งต่อไปนี้
- ข้อความ
- สตริงข้อความ วางสตริงลงในออบเจ็กต์คลิปโดยตรง จากนั้นวางออบเจ็กต์คลิปลงใน คลิปบอร์ด หากต้องการวางสตริง ให้รับออบเจ็กต์คลิปจากคลิปบอร์ดและคัดลอก สตริงลงในพื้นที่เก็บข้อมูลของแอปพลิเคชัน
- URI
-
ออบเจ็กต์
Uri
ที่แสดง URI ในรูปแบบใดก็ได้ ซึ่งส่วนใหญ่ใช้สำหรับการคัดลอกข้อมูลที่ซับซ้อนจากผู้ให้บริการเนื้อหา หากต้องการคัดลอก ข้อมูล ให้ใส่Uri
ออบเจ็กต์ลงในออบเจ็กต์คลิป แล้ววางออบเจ็กต์คลิปลงใน คลิปบอร์ด หากต้องการวางข้อมูล ให้รับออบเจ็กต์คลิป รับออบเจ็กต์Uri
แก้ไขเป็นแหล่งข้อมูล เช่น Content Provider แล้วคัดลอกข้อมูลจาก แหล่งที่มาไปยังที่เก็บข้อมูลของแอปพลิเคชัน - ความตั้งใจ
-
Intent
ซึ่ง รองรับการคัดลอกทางลัดของแอปพลิเคชัน หากต้องการคัดลอกข้อมูล ให้สร้างIntent
วางไว้ในออบเจ็กต์คลิป แล้ววางออบเจ็กต์คลิปลงในคลิปบอร์ด หากต้องการวางข้อมูล ให้รับออบเจ็กต์คลิปแล้วคัดลอกออบเจ็กต์Intent
ลงในพื้นที่หน่วยความจำของแอปพลิเคชัน
คลิปบอร์ดจะเก็บออบเจ็กต์คลิปได้ทีละ 1 รายการเท่านั้น เมื่อแอปพลิเคชันวางออบเจ็กต์คลิปลงในคลิปบอร์ด ออบเจ็กต์คลิปก่อนหน้าจะหายไป
หากต้องการอนุญาตให้ผู้ใช้วางข้อมูลลงในแอปพลิเคชัน คุณไม่จำเป็นต้องจัดการข้อมูลทุกประเภท คุณสามารถตรวจสอบข้อมูลในคลิปบอร์ดก่อนที่จะให้ตัวเลือกแก่ผู้ใช้ในการวางข้อมูล นอกจากจะมีรูปแบบข้อมูลที่แน่นอนแล้ว ออบเจ็กต์คลิปยังมีข้อมูลเมตาที่บอกให้ทราบว่ามี MIME types ใดบ้าง ข้อมูลเมตานี้ช่วยให้คุณตัดสินใจได้ว่าแอปพลิเคชันของคุณสามารถทำสิ่งที่เป็นประโยชน์ กับข้อมูลในคลิปบอร์ดได้หรือไม่ เช่น หากคุณมีแอปพลิเคชันที่จัดการข้อความเป็นหลัก คุณอาจต้องการไม่สนใจออบเจ็กต์คลิปที่มี URI หรือ Intent
นอกจากนี้ คุณยังอาจต้องการอนุญาตให้ผู้ใช้วางข้อความโดยไม่คำนึงถึงรูปแบบข้อมูลในคลิปบอร์ดด้วย หากต้องการทำเช่นนี้ ให้บังคับข้อมูลในคลิปบอร์ดให้เป็นข้อความ แล้ววางข้อความนี้ ซึ่งอธิบายไว้ในส่วนบังคับให้คลิปบอร์ดเป็นข้อความ
คลาสคลิปบอร์ด
ส่วนนี้อธิบายคลาสที่ใช้โดยเฟรมเวิร์กคลิปบอร์ด
ClipboardManager
คลิปบอร์ดของระบบ Android แสดงโดยคลาส global
ClipboardManager
อย่าสร้างอินสแตนซ์ของคลาสนี้โดยตรง แต่ให้รับข้อมูลอ้างอิงโดยเรียกใช้
getSystemService(CLIPBOARD_SERVICE)
แทน
ClipData, ClipData.Item และ ClipDescription
หากต้องการเพิ่มข้อมูลลงในคลิปบอร์ด ให้สร้างออบเจ็กต์
ClipData
ที่มี
คำอธิบายของข้อมูลและข้อมูลนั้น คลิปบอร์ดจะเก็บ ClipData
ได้ครั้งละ 1 รายการ ClipData
มีออบเจ็กต์
ClipDescription
และออบเจ็กต์
ClipData.Item
อย่างน้อย 1 รายการ
ออบเจ็กต์ ClipDescription
มีข้อมูลเมตาเกี่ยวกับคลิป โดยเฉพาะอย่างยิ่ง
มีอาร์เรย์ของประเภท MIME ที่พร้อมใช้งานสำหรับข้อมูลของคลิป นอกจากนี้ ใน Android 12 (API ระดับ 31) ขึ้นไป ข้อมูลเมตาจะรวมข้อมูลเกี่ยวกับว่าออบเจ็กต์มีข้อความที่มีสไตล์หรือไม่ และเกี่ยวกับประเภทของข้อความในออบเจ็กต์
เมื่อวางคลิปลงในคลิปบอร์ด แอปพลิเคชันที่ใช้ในการวางจะเข้าถึงข้อมูลนี้ได้ ซึ่งจะตรวจสอบได้ว่าแอปพลิเคชันนั้นจัดการข้อมูลคลิปได้หรือไม่
ออบเจ็กต์ ClipData.Item
มีข้อความ, URI หรือข้อมูล Intent ดังนี้
- ข้อความ
-
A
CharSequence
- URI
-
A
Uri
โดยปกติแล้วจะมี URI ของผู้ให้บริการเนื้อหา แม้ว่าจะอนุญาตให้ใช้ URI ใดก็ได้ ก็ตาม แอปพลิเคชันที่ให้ข้อมูลจะวาง URI ไว้ในคลิปบอร์ด แอปพลิเคชัน ที่ต้องการวางข้อมูลจะรับ URI จากคลิปบอร์ดและใช้เพื่อเข้าถึงผู้ให้บริการเนื้อหา หรือแหล่งข้อมูลอื่นๆ และดึงข้อมูล - ความตั้งใจ
-
Intent
ข้อมูลประเภทนี้ช่วยให้คุณคัดลอกทางลัดของแอปพลิเคชันไปยัง คลิปบอร์ดได้ จากนั้นผู้ใช้จะวางทางลัดลงในแอปพลิเคชันเพื่อใช้ในภายหลังได้
คุณเพิ่มออบเจ็กต์ ClipData.Item
ลงในคลิปได้มากกว่า 1 รายการ ซึ่งจะช่วยให้ผู้ใช้คัดลอกและ
วางรายการที่เลือกหลายรายการเป็นคลิปเดียวได้ เช่น หากคุณมีวิดเจ็ตรายการที่ให้
ผู้ใช้เลือกได้มากกว่า 1 รายการในครั้งเดียว คุณจะคัดลอกรายการทั้งหมดไปยังคลิปบอร์ดได้พร้อมกัน หากต้องการทำเช่นนี้ ให้สร้าง ClipData.Item
แยกกันสำหรับรายการแต่ละรายการ แล้วเพิ่มออบเจ็กต์ ClipData.Item
ลงในออบเจ็กต์ ClipData
วิธีการอำนวยความสะดวกของ ClipData
คลาส ClipData
มีเมธอดแบบคงที่ที่สะดวกในการสร้างออบเจ็กต์ ClipData
ที่มีออบเจ็กต์ ClipData.Item
รายการเดียวและออบเจ็กต์ ClipDescription
แบบง่ายๆ ดังนี้
-
newPlainText(label, text)
- แสดงผลออบเจ็กต์
ClipData
ที่มีออบเจ็กต์ClipData.Item
เดียว ซึ่งมีสตริงข้อความ ตั้งค่าป้ายกำกับของออบเจ็กต์ClipDescription
เป็นlabel
ประเภท MIME เดียวในClipDescription
คือMIMETYPE_TEXT_PLAIN
ใช้
newPlainText()
เพื่อสร้างคลิปจากสตริงข้อความ -
newUri(resolver, label, URI)
- แสดงผลออบเจ็กต์
ClipData
ซึ่งมีออบเจ็กต์ClipData.Item
รายการเดียว ที่มี URI ตั้งค่าป้ายกำกับของออบเจ็กต์ClipDescription
เป็นlabel
หาก URI เป็น URI ของเนื้อหา นั่นคือหากUri.getScheme()
แสดงผลcontent:
เมธอดจะใช้ออบเจ็กต์ContentResolver
ที่ระบุในresolver
เพื่อเรียกประเภท MIME ที่ใช้ได้จาก ผู้ให้บริการเนื้อหา จากนั้นระบบจะจัดเก็บไว้ในClipDescription
สำหรับ URI ที่ไม่ใช่ URIcontent:
เมธอดจะตั้งค่าประเภท MIME เป็นMIMETYPE_TEXT_URILIST
ใช้
newUri()
เพื่อสร้างคลิปจาก URI โดยเฉพาะอย่างยิ่งcontent:
URI -
newIntent(label, intent)
- แสดงผลออบเจ็กต์
ClipData
ซึ่งมีออบเจ็กต์ClipData.Item
รายการเดียว ที่มีIntent
ตั้งค่าป้ายกำกับของออบเจ็กต์ClipDescription
เป็นlabel
ระบบตั้งค่าประเภท MIME เป็นMIMETYPE_TEXT_INTENT
ใช้
newIntent()
เพื่อสร้างคลิปจากออบเจ็กต์Intent
บังคับให้ข้อมูลในคลิปบอร์ดเป็นข้อความ
แม้ว่าแอปพลิเคชันจะจัดการข้อความเท่านั้น คุณก็สามารถคัดลอกข้อมูลที่ไม่ใช่ข้อความจากคลิปบอร์ดได้โดย
แปลงข้อมูลด้วยเมธอด
ClipData.Item.coerceToText()
เมธอดนี้จะแปลงข้อมูลใน ClipData.Item
เป็นข้อความและส่งคืน CharSequence
ค่าที่ ClipData.Item.coerceToText()
แสดงผลจะอิงตามรูปแบบข้อมูลใน ClipData.Item
ดังนี้
- ข้อความ
-
หาก
ClipData.Item
เป็นข้อความ นั่นคือหากgetText()
ไม่ใช่ค่า Null ฟังก์ชัน coerceToText() จะแสดงผลข้อความ - URI
-
หาก
ClipData.Item
เป็น URI นั่นคือหากgetUri()
ไม่ใช่ค่าว่างcoerceToText()
จะพยายามใช้เป็น URI เนื้อหา- หาก URI เป็น URI ของเนื้อหาและผู้ให้บริการสามารถแสดงผลสตรีมข้อความได้
coerceToText()
จะแสดงผลสตรีมข้อความ - หาก URI เป็น URI ของเนื้อหา แต่ผู้ให้บริการไม่มีสตรีมข้อความ
coerceToText()
จะแสดงผลการแสดง URI การแสดงผลจะเหมือนกับที่Uri.toString()
แสดงผล - หาก URI ไม่ใช่ URI ของเนื้อหา
coerceToText()
จะแสดงผลการแทน URI การแสดงผลจะเหมือนกับที่ได้จากUri.toString()
- หาก URI เป็น URI ของเนื้อหาและผู้ให้บริการสามารถแสดงผลสตรีมข้อความได้
- ความตั้งใจ
- หาก
ClipData.Item
เป็นIntent
นั่นคือหากgetIntent()
ไม่ใช่ค่าว่างcoerceToText()
จะแปลงเป็น URI ของ Intent แล้วแสดงผล การแสดงผลจะเหมือนกับที่Intent.toUri(URI_INTENT_SCHEME)
แสดงผล
กรอบงานของคลิปบอร์ดสรุปได้ดังรูปที่ 2 หากต้องการคัดลอกข้อมูล แอปพลิเคชันจะวางออบเจ็กต์
ClipData
ในคลิปบอร์ดส่วนกลาง ClipboardManager
ClipData
มีออบเจ็กต์ ClipData.Item
อย่างน้อย 1 รายการและออบเจ็กต์
ClipDescription
1 รายการ หากต้องการวางข้อมูล แอปพลิเคชันจะรับ ClipData
,
รับประเภท MIME จาก ClipDescription
และรับข้อมูลจาก
ClipData.Item
หรือจากผู้ให้บริการเนื้อหาที่อ้างอิงโดย
ClipData.Item

คัดลอกไปยังคลิปบอร์ด
หากต้องการคัดลอกข้อมูลไปยังคลิปบอร์ด ให้รับแฮนเดิลไปยังออบเจ็กต์ ClipboardManager
ส่วนกลาง
สร้างออบเจ็กต์ ClipData
และเพิ่มออบเจ็กต์ ClipDescription
และออบเจ็กต์ ClipData.Item
อย่างน้อย 1 รายการลงในออบเจ็กต์นั้น จากนั้นเพิ่มออบเจ็กต์ ClipData
ที่เสร็จสมบูรณ์แล้วลงในออบเจ็กต์
ClipboardManager
ซึ่งจะอธิบายเพิ่มเติมในขั้นตอนต่อไปนี้
- หากคุณคัดลอกข้อมูลโดยใช้ URI ของเนื้อหา ให้ตั้งค่าผู้ให้บริการเนื้อหา
- รับคลิปบอร์ดของระบบ
Kotlin
when(menuItem.itemId) { ... R.id.menu_copy -> { // if the user selects copy // Gets a handle to the clipboard service. val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager } }
Java
... // If the user selects copy. case R.id.menu_copy: // Gets a handle to the clipboard service. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
-
คัดลอกข้อมูลไปยังออบเจ็กต์
ClipData
ใหม่-
สำหรับข้อความ
Kotlin
// Creates a new text clip to put on the clipboard. val clip: ClipData = ClipData.newPlainText("simple text", "Hello, World!")
Java
// Creates a new text clip to put on the clipboard. ClipData clip = ClipData.newPlainText("simple text", "Hello, World!");
-
สำหรับ URI
ข้อมูลโค้ดนี้สร้าง URI โดยการเข้ารหัสรหัสระเบียนลงใน URI ของเนื้อหาสำหรับ ผู้ให้บริการ เทคนิคนี้จะกล่าวถึงอย่างละเอียดในส่วนการเข้ารหัสตัวระบุใน URI
Kotlin
// Creates a Uri using a base Uri and a record ID based on the contact's last // name. Declares the base URI string. const val CONTACTS = "content://com.example.contacts" // Declares a path string for URIs, used to copy data. const val COPY_PATH = "/copy" // Declares the Uri to paste to the clipboard. val copyUri: Uri = Uri.parse("$CONTACTS$COPY_PATH/$lastName") ... // Creates a new URI clip object. The system uses the anonymous // getContentResolver() object to get MIME types from provider. The clip object's // label is "URI", and its data is the Uri previously created. val clip: ClipData = ClipData.newUri(contentResolver, "URI", copyUri)
Java
// Creates a Uri using a base Uri and a record ID based on the contact's last // name. Declares the base URI string. private static final String CONTACTS = "content://com.example.contacts"; // Declares a path string for URIs, used to copy data. private static final String COPY_PATH = "/copy"; // Declares the Uri to paste to the clipboard. Uri copyUri = Uri.parse(CONTACTS + COPY_PATH + "/" + lastName); ... // Creates a new URI clip object. The system uses the anonymous // getContentResolver() object to get MIME types from provider. The clip object's // label is "URI", and its data is the Uri previously created. ClipData clip = ClipData.newUri(getContentResolver(), "URI", copyUri);
-
สำหรับเจตนา
ข้อมูลโค้ดนี้สร้าง
Intent
สำหรับแอปพลิเคชัน แล้ววางไว้ในออบเจ็กต์คลิปKotlin
// Creates the Intent. val appIntent = Intent(this, com.example.demo.myapplication::class.java) ... // Creates a clip object with the Intent in it. Its label is "Intent" // and its data is the Intent object created previously. val clip: ClipData = ClipData.newIntent("Intent", appIntent)
Java
// Creates the Intent. Intent appIntent = new Intent(this, com.example.demo.myapplication.class); ... // Creates a clip object with the Intent in it. Its label is "Intent" // and its data is the Intent object created previously. ClipData clip = ClipData.newIntent("Intent", appIntent);
-
สำหรับข้อความ
-
วางออบเจ็กต์คลิปใหม่ลงในคลิปบอร์ด
Kotlin
// Set the clipboard's primary clip. clipboard.setPrimaryClip(clip)
Java
// Set the clipboard's primary clip. clipboard.setPrimaryClip(clip);
แสดงความคิดเห็นเมื่อคัดลอกไปยังคลิปบอร์ด
ผู้ใช้คาดหวังว่าจะได้รับข้อเสนอแนะด้านภาพเมื่อแอปคัดลอกเนื้อหาไปยังคลิปบอร์ด ระบบจะดำเนินการนี้โดยอัตโนมัติสำหรับผู้ใช้ใน Android 13 ขึ้นไป แต่ต้องติดตั้งใช้งานด้วยตนเองในเวอร์ชันก่อนหน้า
ตั้งแต่ Android 13 เป็นต้นไป ระบบจะแสดงการยืนยันด้วยภาพมาตรฐานเมื่อมีการเพิ่มเนื้อหา ลงในคลิปบอร์ด การยืนยันใหม่จะทำสิ่งต่อไปนี้
- ยืนยันว่าคัดลอกเนื้อหาสำเร็จแล้ว
- แสดงตัวอย่างเนื้อหาที่คัดลอก

ใน Android 12L (API ระดับ 32) และต่ำกว่า ผู้ใช้อาจไม่แน่ใจว่าคัดลอกเนื้อหาสำเร็จหรือไม่หรือคัดลอกอะไร ฟีเจอร์นี้จะกำหนดมาตรฐานการแจ้งเตือนต่างๆ ที่แอปแสดงหลังจากคัดลอก และช่วยให้ผู้ใช้ควบคุมคลิปบอร์ดได้มากขึ้น
หลีกเลี่ยงการแจ้งเตือนที่ซ้ำกัน
ใน Android 12L (API ระดับ 32) และต่ำกว่า เราขอแนะนำให้แจ้งเตือนผู้ใช้เมื่อคัดลอกสำเร็จ
โดยแสดงความคิดเห็นในแอปแบบภาพโดยใช้วิดเจ็ต เช่น Toast
หรือ
Snackbar
หลังจากคัดลอก
เราขอแนะนำอย่างยิ่งให้นำโทสต์ หรือแถบแสดงข้อความที่แสดงหลังจากคัดลอกในแอปสำหรับ Android 13 ขึ้นไปออก เพื่อหลีกเลี่ยงการแสดงข้อมูลซ้ำ


ตัวอย่างวิธีติดตั้งใช้งานมีดังนี้
fun textCopyThenPost(textCopied:String) { val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager // When setting the clipboard text. clipboardManager.setPrimaryClip(ClipData.newPlainText ("", textCopied)) // Only show a toast for Android 12 and lower. if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) Toast.makeText(context, “Copied”, Toast.LENGTH_SHORT).show() }
เพิ่มเนื้อหาที่ละเอียดอ่อนลงในคลิปบอร์ด
หากแอปอนุญาตให้ผู้ใช้คัดลอกเนื้อหาที่ละเอียดอ่อนไปยังคลิปบอร์ด เช่น รหัสผ่านหรือข้อมูลบัตรเครดิต
คุณต้องเพิ่ม Flag ไปยัง ClipDescription
ใน ClipData
ก่อนเรียกใช้ ClipboardManager.setPrimaryClip()
การเพิ่มฟีเจอร์นี้จะป้องกันไม่ให้เนื้อหาที่มีความละเอียดอ่อน
ปรากฏในการยืนยันด้วยภาพของเนื้อหาที่คัดลอกใน Android 13 ขึ้นไป


หากต้องการแจ้งเนื้อหาที่ละเอียดอ่อน ให้เพิ่มบูลีนพิเศษไปยัง ClipDescription
แอปทั้งหมดต้องทำ
เช่นนี้ ไม่ว่าระดับ API ที่กำหนดเป้าหมายจะเป็นระดับใดก็ตาม
// If your app is compiled with the API level 33 SDK or higher. clipData.apply { description.extras = PersistableBundle().apply { putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true) } } // If your app is compiled with a lower SDK. clipData.apply { description.extras = PersistableBundle().apply { putBoolean("android.content.extra.IS_SENSITIVE", true) } }
วางจากคลิปบอร์ด
ดังที่อธิบายไว้ก่อนหน้านี้ ให้วางข้อมูลจากคลิปบอร์ดโดยรับออบเจ็กต์คลิปบอร์ดส่วนกลาง รับออบเจ็กต์คลิป ดูข้อมูลของออบเจ็กต์ และหากเป็นไปได้ ให้คัดลอกข้อมูลจากออบเจ็กต์คลิป ไปยังพื้นที่เก็บข้อมูลของคุณเอง ส่วนนี้จะอธิบายโดยละเอียดถึงวิธีวางข้อมูลในคลิปบอร์ดทั้ง 3 รูปแบบ
วางข้อความธรรมดา
หากต้องการวางข้อความธรรมดา ให้รับคลิปบอร์ดส่วนกลางและตรวจสอบว่าคลิปบอร์ดสามารถส่งคืนข้อความธรรมดาได้ จากนั้นรับ
ออบเจ็กต์คลิปและคัดลอกข้อความไปยังที่เก็บข้อมูลของคุณเองโดยใช้ getText()
ตามที่อธิบายไว้ใน
ขั้นตอนต่อไปนี้
- รับออบเจ็กต์
ClipboardManager
ส่วนกลางโดยใช้getSystemService(CLIPBOARD_SERVICE)
นอกจากนี้ ให้ประกาศตัวแปรร่วมเพื่อเก็บ ข้อความที่วางKotlin
var clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager var pasteData: String = ""
Java
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); String pasteData = "";
- พิจารณาว่าคุณต้องเปิดหรือปิดใช้ตัวเลือก "วาง" ในกิจกรรมปัจจุบันหรือไม่
ตรวจสอบว่าคลิปบอร์ดมีคลิปและคุณสามารถจัดการประเภทข้อมูล
ที่แสดงโดยคลิปได้
Kotlin
// Gets the ID of the "paste" menu item. val pasteItem: MenuItem = menu.findItem(R.id.menu_paste) // If the clipboard doesn't contain data, disable the paste menu item. // If it does contain data, decide whether you can handle the data. pasteItem.isEnabled = when { !clipboard.hasPrimaryClip() -> { false } !(clipboard.primaryClipDescription.hasMimeType(MIMETYPE_TEXT_PLAIN)) -> { // Disables the paste menu item, since the clipboard has data but it // isn't plain text. false } else -> { // Enables the paste menu item, since the clipboard contains plain text. true } }
Java
// Gets the ID of the "paste" menu item. MenuItem pasteItem = menu.findItem(R.id.menu_paste); // If the clipboard doesn't contain data, disable the paste menu item. // If it does contain data, decide whether you can handle the data. if (!(clipboard.hasPrimaryClip())) { pasteItem.setEnabled(false); } else if (!(clipboard.getPrimaryClipDescription().hasMimeType(MIMETYPE_TEXT_PLAIN))) { // Disables the paste menu item, since the clipboard has data but // it isn't plain text. pasteItem.setEnabled(false); } else { // Enables the paste menu item, since the clipboard contains plain text. pasteItem.setEnabled(true); }
- คัดลอกข้อมูลจากคลิปบอร์ด จุดนี้ในโค้ดจะเข้าถึงได้ก็ต่อเมื่อเปิดใช้รายการเมนู "วาง" เท่านั้น ดังนั้นคุณจึงถือได้ว่าคลิปบอร์ดมีข้อความธรรมดา คุณยังไม่ทราบว่ามีสตริงข้อความหรือ URI ที่ชี้ไปยังข้อความธรรมดาหรือไม่
ข้อมูลโค้ดต่อไปนี้จะทดสอบการดำเนินการนี้ แต่จะแสดงเฉพาะโค้ดสำหรับการจัดการข้อความธรรมดา
Kotlin
when (menuItem.itemId) { ... R.id.menu_paste -> { // Responds to the user selecting "paste". // Examines the item on the clipboard. If getText() doesn't return null, // the clip item contains the text. Assumes that this application can only // handle one item at a time. val item = clipboard.primaryClip.getItemAt(0) // Gets the clipboard as text. pasteData = item.text return if (pasteData != null) { // If the string contains data, then the paste operation is done. true } else { // The clipboard doesn't contain text. If it contains a URI, // attempts to get data from it. val pasteUri: Uri? = item.uri if (pasteUri != null) { // If the URI contains something, try to get text from it. // Calls a routine to resolve the URI and get data from it. // This routine isn't presented here. pasteData = resolveUri(pasteUri) true } else { // Something is wrong. The MIME type was plain text, but the // clipboard doesn't contain text or a Uri. Report an error. Log.e(TAG,"Clipboard contains an invalid data type") false } } } }
Java
// Responds to the user selecting "paste". case R.id.menu_paste: // Examines the item on the clipboard. If getText() does not return null, // the clip item contains the text. Assumes that this application can only // handle one item at a time. ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0); // Gets the clipboard as text. pasteData = item.getText(); // If the string contains data, then the paste operation is done. if (pasteData != null) { return true; // The clipboard doesn't contain text. If it contains a URI, attempts to get // data from it. } else { Uri pasteUri = item.getUri(); // If the URI contains something, try to get text from it. if (pasteUri != null) { // Calls a routine to resolve the URI and get data from it. // This routine isn't presented here. pasteData = resolveUri(Uri); return true; } else { // Something is wrong. The MIME type is plain text, but the // clipboard doesn't contain text or a Uri. Report an error. Log.e(TAG, "Clipboard contains an invalid data type"); return false; } }
วางข้อมูลจาก URI ของเนื้อหา
หากออบเจ็กต์ ClipData.Item
มี URI เนื้อหาและคุณพิจารณาว่าสามารถ
จัดการประเภท MIME อย่างใดอย่างหนึ่งได้ ให้สร้าง ContentResolver
และเรียกใช้เมธอด Content
Provider ที่เหมาะสมเพื่อดึงข้อมูล
ขั้นตอนต่อไปนี้อธิบายวิธีรับข้อมูลจากผู้ให้บริการเนื้อหาโดยอิงตาม URI ของเนื้อหา ในคลิปบอร์ด โดยจะตรวจสอบว่ามีประเภท MIME ที่แอปพลิเคชันใช้ได้จากผู้ให้บริการหรือไม่
-
ประกาศตัวแปรร่วมให้มีประเภท MIME ดังนี้
Kotlin
// Declares a MIME type constant to match against the MIME types offered // by the provider. const val MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact"
Java
// Declares a MIME type constant to match against the MIME types offered by // the provider. public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact";
- รับคลิปบอร์ดส่วนกลาง นอกจากนี้ ให้รับตัวแก้ไขเนื้อหาเพื่อให้คุณเข้าถึงผู้ให้บริการเนื้อหาได้
Kotlin
// Gets a handle to the Clipboard Manager. val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager // Gets a content resolver instance. val cr = contentResolver
Java
// Gets a handle to the Clipboard Manager. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); // Gets a content resolver instance. ContentResolver cr = getContentResolver();
- รับคลิปหลักจากคลิปบอร์ดและรับเนื้อหาเป็น URI โดยทำดังนี้
Kotlin
// Gets the clipboard data from the clipboard. val clip: ClipData? = clipboard.primaryClip clip?.run { // Gets the first item from the clipboard data. val item: ClipData.Item = getItemAt(0) // Tries to get the item's contents as a URI. val pasteUri: Uri? = item.uri
Java
// Gets the clipboard data from the clipboard. ClipData clip = clipboard.getPrimaryClip(); if (clip != null) { // Gets the first item from the clipboard data. ClipData.Item item = clip.getItemAt(0); // Tries to get the item's contents as a URI. Uri pasteUri = item.getUri();
- ทดสอบว่า URI เป็น URI เนื้อหาหรือไม่โดยเรียกใช้
getType(Uri)
เมธอดนี้จะแสดงผลเป็น Null หากUri
ไม่ได้ชี้ไปยังผู้ให้บริการเนื้อหาที่ถูกต้องKotlin
// If the clipboard contains a URI reference... pasteUri?.let { // ...is this a content URI? val uriMimeType: String? = cr.getType(it)
Java
// If the clipboard contains a URI reference... if (pasteUri != null) { // ...is this a content URI? String uriMimeType = cr.getType(pasteUri);
- ทดสอบว่าผู้ให้บริการเนื้อหารองรับประเภท MIME ที่แอปพลิเคชันเข้าใจหรือไม่ หากมี ให้เรียกใช้
ContentResolver.query()
เพื่อรับข้อมูล ค่าที่ส่งกลับคือCursor
Kotlin
// If the return value isn't null, the Uri is a content Uri. uriMimeType?.takeIf { // Does the content provider offer a MIME type that the current // application can use? it == MIME_TYPE_CONTACT }?.apply { // Get the data from the content provider. cr.query(pasteUri, null, null, null, null)?.use { pasteCursor -> // If the Cursor contains data, move to the first record. if (pasteCursor.moveToFirst()) { // Get the data from the Cursor here. // The code varies according to the format of the data model. } // Kotlin `use` automatically closes the Cursor. } } } }
Java
// If the return value isn't null, the Uri is a content Uri. if (uriMimeType != null) { // Does the content provider offer a MIME type that the current // application can use? if (uriMimeType.equals(MIME_TYPE_CONTACT)) { // Get the data from the content provider. Cursor pasteCursor = cr.query(uri, null, null, null, null); // If the Cursor contains data, move to the first record. if (pasteCursor != null) { if (pasteCursor.moveToFirst()) { // Get the data from the Cursor here. // The code varies according to the format of the data model. } } // Close the Cursor. pasteCursor.close(); } } } }
วางความตั้งใจ
หากต้องการวาง Intent ให้รับคลิปบอร์ดส่วนกลางก่อน ตรวจสอบออบเจ็กต์ ClipData.Item
เพื่อดูว่ามี Intent
หรือไม่ จากนั้นเรียกใช้ getIntent()
เพื่อคัดลอก
Intent ไปยังที่เก็บข้อมูลของคุณเอง ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นถึงการดำเนินการนี้
Kotlin
// Gets a handle to the Clipboard Manager. val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager // Checks whether the clip item contains an Intent by testing whether // getIntent() returns null. val pasteIntent: Intent? = clipboard.primaryClip?.getItemAt(0)?.intent if (pasteIntent != null) { // Handle the Intent. } else { // Ignore the clipboard, or issue an error if // you expect an Intent to be on the clipboard. }
Java
// Gets a handle to the Clipboard Manager. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); // Checks whether the clip item contains an Intent, by testing whether // getIntent() returns null. Intent pasteIntent = clipboard.getPrimaryClip().getItemAt(0).getIntent(); if (pasteIntent != null) { // Handle the Intent. } else { // Ignore the clipboard, or issue an error if // you expect an Intent to be on the clipboard. }
การแจ้งเตือนของระบบจะแสดงเมื่อแอปเข้าถึงข้อมูลในคลิปบอร์ด
ใน Android 12 (API ระดับ 31) ขึ้นไป โดยปกติแล้วระบบจะแสดงข้อความ Toast เมื่อแอปของคุณ
เรียกใช้
getPrimaryClip()
ข้อความภายในข้อความมีรูปแบบต่อไปนี้
APP pasted from your clipboard
ระบบจะไม่แสดงข้อความป๊อปอัปเมื่อแอปของคุณทำอย่างใดอย่างหนึ่งต่อไปนี้
- เข้าถึง
ClipData
จากแอปของคุณเอง - เข้าถึง
ClipData
จากแอปหนึ่งๆ ซ้ำๆ การแจ้งเตือนจะปรากฏขึ้นเมื่อ แอปของคุณเข้าถึงข้อมูลจากแอปนั้นเป็นครั้งแรกเท่านั้น - เรียกข้อมูลเมตาสำหรับออบเจ็กต์คลิป เช่น โดยการเรียก
getPrimaryClipDescription()
แทนgetPrimaryClip()
ใช้ผู้ให้บริการเนื้อหาเพื่อคัดลอกข้อมูลที่ซับซ้อน
ผู้ให้บริการเนื้อหารองรับการคัดลอกข้อมูลที่ซับซ้อน เช่น บันทึกฐานข้อมูลหรือสตรีมไฟล์ หากต้องการคัดลอก ข้อมูล ให้วาง URI ของเนื้อหาลงในคลิปบอร์ด จากนั้นแอปพลิเคชันที่วางจะรับ URI นี้จากคลิปบอร์ดและใช้เพื่อดึงข้อมูลฐานข้อมูลหรือตัวอธิบายสตรีมไฟล์
เนื่องจากแอปพลิเคชันที่วางมีเพียง URI เนื้อหาสำหรับข้อมูลของคุณ จึงต้องทราบว่าควรดึงข้อมูลใด คุณระบุข้อมูลนี้ได้โดยการเข้ารหัสตัวระบุสำหรับข้อมูล ใน URI เอง หรือจะระบุ URI ที่ไม่ซ้ำกันซึ่งแสดงข้อมูลที่คุณต้องการคัดลอกก็ได้ เทคนิคที่คุณเลือกจะขึ้นอยู่กับการจัดระเบียบข้อมูล
ส่วนต่อไปนี้จะอธิบายวิธีตั้งค่า URI ระบุข้อมูลที่ซับซ้อน และระบุสตรีมไฟล์ คำอธิบายจะถือว่าคุณคุ้นเคยกับหลักการทั่วไปของการออกแบบผู้ให้บริการเนื้อหา
เข้ารหัสตัวระบุใน URI
เทคนิคที่มีประโยชน์ในการคัดลอกข้อมูลไปยังคลิปบอร์ดด้วย URI คือการเข้ารหัสตัวระบุสำหรับ ข้อมูลใน URI เอง จากนั้นผู้ให้บริการเนื้อหาจะรับตัวระบุจาก URI และใช้ เพื่อดึงข้อมูลได้ แอปพลิเคชันที่วางไม่จำเป็นต้องทราบว่ามีตัวระบุอยู่ เพียงแค่ต้องรับ "ข้อมูลอ้างอิง" ซึ่งก็คือ URI บวกตัวระบุจากคลิปบอร์ด ส่งให้ผู้ให้บริการเนื้อหา แล้วรับข้อมูลกลับมา
โดยปกติแล้ว คุณจะเข้ารหัสตัวระบุลงใน URI ของเนื้อหาด้วยการต่อท้ายตัวระบุไว้ที่ท้าย URI เช่น สมมติว่าคุณกำหนด URI ของผู้ให้บริการเป็นสตริงต่อไปนี้
"content://com.example.contacts"
หากต้องการเข้ารหัสชื่อลงใน URI นี้ ให้ใช้ข้อมูลโค้ดต่อไปนี้
Kotlin
val uriString = "content://com.example.contacts/Smith" // uriString now contains content://com.example.contacts/Smith. // Generates a uri object from the string representation. val copyUri = Uri.parse(uriString)
Java
String uriString = "content://com.example.contacts" + "/" + "Smith"; // uriString now contains content://com.example.contacts/Smith. // Generates a uri object from the string representation. Uri copyUri = Uri.parse(uriString);
หากใช้ผู้ให้บริการเนื้อหาอยู่แล้ว คุณอาจต้องเพิ่มเส้นทาง URI ใหม่ที่ระบุว่า URI ใช้สำหรับการคัดลอก ตัวอย่างเช่น สมมติว่าคุณมีเส้นทาง URI ต่อไปนี้อยู่แล้ว
"content://com.example.contacts/people" "content://com.example.contacts/people/detail" "content://com.example.contacts/people/images"
คุณเพิ่มเส้นทางอื่นสำหรับการคัดลอก URI ได้โดยทำดังนี้
"content://com.example.contacts/copying"
จากนั้นคุณจะตรวจหา URI "สำเนา" ได้โดยการจับคู่รูปแบบและจัดการด้วยโค้ดที่ เฉพาะสำหรับการคัดลอกและวาง
โดยปกติแล้ว คุณจะใช้เทคนิคการเข้ารหัสหากใช้ผู้ให้บริการเนื้อหา ฐานข้อมูลภายใน หรือตารางภายในเพื่อจัดระเบียบข้อมูลอยู่แล้ว ในกรณีเหล่านี้ คุณมีข้อมูลหลายรายการที่ต้องการคัดลอก และอาจมีตัวระบุที่ไม่ซ้ำกันสำหรับแต่ละรายการ เมื่อได้รับคำค้นหาจากแอปพลิเคชันที่วาง คุณสามารถค้นหาข้อมูลตามตัวระบุและส่งคืนได้
หากไม่มีข้อมูลหลายส่วน คุณอาจไม่จำเป็นต้องเข้ารหัสตัวระบุ คุณใช้ URI ที่ไม่ซ้ำกันสำหรับผู้ให้บริการได้ เมื่อได้รับการค้นหา ผู้ให้บริการจะแสดงข้อมูลที่ตนมีอยู่ในปัจจุบัน
คัดลอกโครงสร้างข้อมูล
ตั้งค่าผู้ให้บริการเนื้อหาสำหรับการคัดลอกและวางข้อมูลที่ซับซ้อนเป็นคลาสย่อยของ
ContentProvider
คอมโพเนนต์ เข้ารหัส URI ที่คุณวางไว้ในคลิปบอร์ดเพื่อให้ชี้ไปยังระเบียนที่ต้องการ
ระบุ นอกจากนี้ ให้พิจารณาสถานะปัจจุบันของแอปพลิเคชันด้วย
- หากมีผู้ให้บริการเนื้อหาอยู่แล้ว คุณสามารถเพิ่มฟังก์ชันการทำงานได้ คุณอาจต้องแก้ไขเฉพาะเมธอด
query()
เพื่อจัดการ URI ที่มาจากแอปพลิเคชันที่ต้องการวางข้อมูล คุณอาจต้องการแก้ไขวิธีการเพื่อจัดการรูปแบบ URI "copy" - หากแอปพลิเคชันของคุณมีฐานข้อมูลภายใน คุณอาจต้องย้ายฐานข้อมูลนี้ ไปยัง Content Provider เพื่อให้คัดลอกข้อมูลจากฐานข้อมูลได้ง่ายขึ้น
- หากไม่ได้ใช้ฐานข้อมูล คุณสามารถใช้ Content Provider แบบง่ายๆ ซึ่งมี วัตถุประสงค์เพียงอย่างเดียวคือการเสนอข้อมูลให้กับแอปพลิเคชันที่วางจากคลิปบอร์ด
ในผู้ให้บริการเนื้อหา ให้ลบล้างเมธอดต่อไปนี้อย่างน้อย
-
query()
- แอปพลิเคชันที่วางจะถือว่าสามารถรับข้อมูลของคุณได้โดยใช้วิธีนี้กับ URI ที่คุณ วางไว้ในคลิปบอร์ด หากต้องการรองรับการคัดลอก ให้ใช้วิธีนี้เพื่อตรวจหา URI ที่มีเส้นทาง "copy" พิเศษ จากนั้นแอปพลิเคชันจะสร้าง URI "สำเนา" เพื่อวางใน คลิปบอร์ด ซึ่งมีเส้นทางการคัดลอกและตัวชี้ไปยังระเบียนที่แน่นอนที่คุณต้องการคัดลอก
-
getType()
- เมธอดนี้ต้องแสดงผลประเภท MIME สำหรับข้อมูลที่คุณต้องการคัดลอก เมธอด
newUri()
เรียกgetType()
เพื่อใส่ประเภท MIME ลงในออบเจ็กต์ClipData
ใหม่ประเภท MIME สำหรับข้อมูลที่ซับซ้อนอธิบายไว้ใน ผู้ให้บริการเนื้อหา
คุณไม่จำเป็นต้องมีวิธีการของผู้ให้บริการเนื้อหารายอื่นๆ เช่น
insert()
หรือ
update()
แอปพลิเคชันที่วางจะต้องได้รับ MIME ประเภทที่รองรับและคัดลอกข้อมูลจากผู้ให้บริการเท่านั้น
หากคุณมีวิธีการเหล่านี้อยู่แล้ว วิธีการดังกล่าวจะไม่รบกวนการดำเนินการคัดลอก
ข้อมูลโค้ดต่อไปนี้แสดงวิธีตั้งค่าแอปพลิเคชันเพื่อคัดลอกข้อมูลที่ซับซ้อน
-
ในค่าคงที่ส่วนกลางของแอปพลิเคชัน ให้ประกาศสตริง URI ฐานและเส้นทางที่ ระบุสตริง URI ที่คุณใช้เพื่อคัดลอกข้อมูล และประกาศประเภท MIME สำหรับข้อมูลที่คัดลอกด้วย
Kotlin
// Declares the base URI string. private const val CONTACTS = "content://com.example.contacts" // Declares a path string for URIs that you use to copy data. private const val COPY_PATH = "/copy" // Declares a MIME type for the copied data. const val MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact"
Java
// Declares the base URI string. private static final String CONTACTS = "content://com.example.contacts"; // Declares a path string for URIs that you use to copy data. private static final String COPY_PATH = "/copy"; // Declares a MIME type for the copied data. public static final String MIME_TYPE_CONTACT = "vnd.android.cursor.item/vnd.example.contact";
- ในกิจกรรมที่ผู้ใช้คัดลอกข้อมูล ให้ตั้งค่าโค้ดเพื่อคัดลอกข้อมูลไปยังคลิปบอร์ด
เมื่อได้รับคำขอคัดลอก ให้วาง URI ไว้ในคลิปบอร์ด
Kotlin
class MyCopyActivity : Activity() { ... when(item.itemId) { R.id.menu_copy -> { // The user has selected a name and is requesting a copy. // Appends the last name to the base URI. // The name is stored in "lastName". uriString = "$CONTACTS$COPY_PATH/$lastName" // Parses the string into a URI. val copyUri: Uri? = Uri.parse(uriString) // Gets a handle to the clipboard service. val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip: ClipData = ClipData.newUri(contentResolver, "URI", copyUri) // Sets the clipboard's primary clip. clipboard.setPrimaryClip(clip) } }
Java
public class MyCopyActivity extends Activity { ... // The user has selected a name and is requesting a copy. case R.id.menu_copy: // Appends the last name to the base URI. // The name is stored in "lastName". uriString = CONTACTS + COPY_PATH + "/" + lastName; // Parses the string into a URI. Uri copyUri = Uri.parse(uriString); // Gets a handle to the clipboard service. ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newUri(getContentResolver(), "URI", copyUri); // Sets the clipboard's primary clip. clipboard.setPrimaryClip(clip);
-
ในขอบเขตทั่วโลกของผู้ให้บริการเนื้อหา ให้สร้างตัวจับคู่ URI และเพิ่มรูปแบบ URI ที่ ตรงกับ URI ที่คุณวางไว้ในคลิปบอร์ด
Kotlin
// A Uri Match object that simplifies matching content URIs to patterns. private val sUriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply { // Adds a matcher for the content URI. It matches. // "content://com.example.contacts/copy/*" addURI(CONTACTS, "names/*", GET_SINGLE_CONTACT) } // An integer to use in switching based on the incoming URI pattern. private const val GET_SINGLE_CONTACT = 0 ... class MyCopyProvider : ContentProvider() { ... }
Java
public class MyCopyProvider extends ContentProvider { ... // A Uri Match object that simplifies matching content URIs to patterns. private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); // An integer to use in switching based on the incoming URI pattern. private static final int GET_SINGLE_CONTACT = 0; ... // Adds a matcher for the content URI. It matches // "content://com.example.contacts/copy/*" sUriMatcher.addURI(CONTACTS, "names/*", GET_SINGLE_CONTACT);
-
ตั้งค่า
query()
วิธี วิธีนี้สามารถจัดการรูปแบบ URI ที่แตกต่างกันได้ ขึ้นอยู่กับวิธีที่คุณเขียนโค้ด แต่จะแสดงเฉพาะรูปแบบสำหรับการดำเนินการคัดลอกไปยังคลิปบอร์ดเท่านั้นKotlin
// Sets up your provider's query() method. override fun query( uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String? ): Cursor? { ... // When based on the incoming content URI: when(sUriMatcher.match(uri)) { GET_SINGLE_CONTACT -> { // Queries and returns the contact for the requested name. Decodes // the incoming URI, queries the data model based on the last name, // and returns the result as a Cursor. } } ... }
Java
// Sets up your provider's query() method. public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { ... // Switch based on the incoming content URI. switch (sUriMatcher.match(uri)) { case GET_SINGLE_CONTACT: // Queries and returns the contact for the requested name. Decodes the // incoming URI, queries the data model based on the last name, and // returns the result as a Cursor. ... }
-
ตั้งค่าเมธอด
getType()
เพื่อแสดงผลประเภท MIME ที่เหมาะสมสำหรับข้อมูลที่คัดลอก ดังนี้Kotlin
// Sets up your provider's getType() method. override fun getType(uri: Uri): String? { ... return when(sUriMatcher.match(uri)) { GET_SINGLE_CONTACT -> MIME_TYPE_CONTACT ... } }
Java
// Sets up your provider's getType() method. public String getType(Uri uri) { ... switch (sUriMatcher.match(uri)) { case GET_SINGLE_CONTACT: return (MIME_TYPE_CONTACT); ... } }
ส่วนวางข้อมูลจาก URI ของเนื้อหาอธิบายวิธีรับ URI ของเนื้อหาจากคลิปบอร์ดและใช้เพื่อรับและวางข้อมูล
คัดลอกสตรีมข้อมูล
คุณสามารถคัดลอกและวางข้อความและข้อมูลไบนารีจำนวนมากเป็นสตรีมได้ ข้อมูลอาจมีรูปแบบดังต่อไปนี้
- ไฟล์ที่จัดเก็บไว้ในอุปกรณ์จริง
- สตรีมจากซ็อกเก็ต
- ข้อมูลจำนวนมากที่จัดเก็บไว้ในระบบฐานข้อมูลพื้นฐานของผู้ให้บริการ
ผู้ให้บริการเนื้อหาสำหรับสตรีมข้อมูลจะให้สิทธิ์เข้าถึงข้อมูลของตนด้วยออบเจ็กต์ตัวอธิบายไฟล์
เช่น
AssetFileDescriptor
แทนออบเจ็กต์ Cursor
แอปพลิเคชันที่วางจะอ่านสตรีมข้อมูลโดยใช้
ตัวอธิบายไฟล์นี้
หากต้องการตั้งค่าแอปพลิเคชันให้คัดลอกสตรีมข้อมูลกับผู้ให้บริการ ให้ทำตามขั้นตอนต่อไปนี้
-
ตั้งค่า URI ของเนื้อหาสําหรับสตรีมข้อมูลที่คุณวางไว้ในคลิปบอร์ด ตัวเลือก
ในการดำเนินการนี้มีดังนี้
- เข้ารหัสตัวระบุสำหรับสตรีมข้อมูลลงใน URI ตามที่อธิบายไว้ในส่วนเข้ารหัสตัวระบุใน URI จากนั้นให้ดูแลตารางในผู้ให้บริการที่มีตัวระบุและชื่อสตรีมที่เกี่ยวข้อง
- เข้ารหัสชื่อสตรีมใน URI โดยตรง
- ใช้ URI ที่ไม่ซ้ำกันซึ่งจะแสดงสตรีมปัจจุบันจากผู้ให้บริการเสมอ หากคุณ ใช้ตัวเลือกนี้ โปรดอย่าลืมอัปเดตผู้ให้บริการให้ชี้ไปยังสตรีมอื่น ทุกครั้งที่คุณคัดลอกสตรีมไปยังคลิปบอร์ดโดยใช้ URI
- ระบุประเภท MIME สำหรับสตรีมข้อมูลแต่ละประเภทที่คุณวางแผนจะเสนอ แอปพลิเคชันที่วาง ต้องใช้ข้อมูลนี้เพื่อพิจารณาว่าจะวางข้อมูลในคลิปบอร์ดได้หรือไม่
- ใช้
ContentProvider
วิธีใดวิธีหนึ่งที่แสดงผลตัวอธิบายไฟล์สำหรับ สตรีม หากเข้ารหัสตัวระบุใน URI ของเนื้อหา ให้ใช้วิธีนี้เพื่อกำหนดสตรีมที่จะเปิด - หากต้องการคัดลอกสตรีมข้อมูลไปยังคลิปบอร์ด ให้สร้าง URI ของเนื้อหาและวางไว้ใน คลิปบอร์ด
หากต้องการวางสตรีมข้อมูล แอปพลิเคชันจะรับคลิปจากคลิปบอร์ด รับ URI และใช้
ในคำสั่งเรียกใช้เมธอดตัวอธิบายไฟล์ ContentResolver
ที่เปิดสตรีม เมธอด
ContentResolver
จะเรียกเมธอด ContentProvider
ที่เกี่ยวข้อง
โดยส่ง URI ของเนื้อหาไปให้ ผู้ให้บริการจะแสดงตัวอธิบายไฟล์ไปยังเมธอด
ContentResolver
จากนั้นแอปพลิเคชันที่วางจะมีหน้าที่อ่าน
ข้อมูลจากสตรีม
รายการต่อไปนี้แสดงวิธีการระบุไฟล์ที่สำคัญที่สุดสำหรับผู้ให้บริการเนื้อหา แต่ละรายการมีเมธอด ContentResolver
ที่สอดคล้องกันโดยมีสตริง
"Descriptor" ต่อท้ายชื่อเมธอด ตัวอย่างเช่น ContentResolver
อนาล็อกของ
openAssetFile()
คือ
openAssetFileDescriptor()
-
openTypedAssetFile()
-
วิธีนี้จะแสดงตัวอธิบายไฟล์ชิ้นงาน แต่จะแสดงก็ต่อเมื่อผู้ให้บริการรองรับประเภท MIME ที่ระบุเท่านั้น ผู้เรียกใช้ ซึ่งก็คือแอปพลิเคชันที่ทำการวาง จะระบุรูปแบบประเภท MIME ผู้ให้บริการเนื้อหาของแอปพลิเคชันที่คัดลอก URI ไปยัง คลิปบอร์ดจะส่งคืน
AssetFileDescriptor
แฮนเดิลไฟล์หากระบุประเภท MIME นั้นได้ และจะส่งข้อยกเว้นหากระบุไม่ได้วิธีนี้จะจัดการส่วนย่อยของไฟล์ คุณสามารถใช้ฟีเจอร์นี้เพื่ออ่านเนื้อหาที่ผู้ให้บริการเนื้อหาคัดลอกไปยังคลิปบอร์ดได้
-
openAssetFile()
-
เมธอดนี้เป็นรูปแบบทั่วไปของ
openTypedAssetFile()
โดยจะไม่กรอง ประเภท MIME ที่อนุญาต แต่จะอ่านส่วนย่อยของไฟล์ได้ -
openFile()
-
นี่คือรูปแบบทั่วไปของ
openAssetFile()
อ่านส่วนย่อยของ ไฟล์ไม่ได้
คุณเลือกใช้เมธอด
openPipeHelper()
กับเมธอดตัวอธิบายไฟล์ได้ ซึ่งช่วยให้แอปพลิเคชันที่วางอ่านข้อมูลสตรีมใน
เธรดเบื้องหลังโดยใช้ไปป์ได้ หากต้องการใช้วิธีนี้ ให้ใช้
ContentProvider.PipeDataWriter
อินเทอร์เฟซ
ออกแบบฟังก์ชันการคัดลอกและวางที่มีประสิทธิภาพ
หากต้องการออกแบบฟังก์ชันการคัดลอกและวางที่มีประสิทธิภาพสำหรับแอปพลิเคชัน โปรดคำนึงถึงประเด็นต่อไปนี้
- โดยในแต่ละครั้งจะมีคลิปบอร์ดได้เพียงคลิปเดียว การคัดลอกใหม่โดยแอปพลิเคชันใดๆ ในระบบจะเขียนทับคลิปก่อนหน้า เนื่องจากผู้ใช้อาจออกจากแอปพลิเคชันของคุณและคัดลอกก่อนที่จะกลับมา คุณจึงไม่สามารถถือว่าคลิปบอร์ดมีคลิปที่ผู้ใช้คัดลอกไว้ก่อนหน้านี้ในแอปพลิเคชันของคุณ
-
วัตถุ
ClipData.Item
หลายรายการต่อคลิปมีจุดประสงค์เพื่อ รองรับการคัดลอกและวางรายการที่เลือกหลายรายการแทนที่จะเป็นรูปแบบต่างๆ ของ การอ้างอิงถึงรายการที่เลือกรายการเดียว โดยปกติแล้ว คุณต้องการให้ClipData.Item
ออบเจ็กต์ทั้งหมดในคลิปมีรูปแบบเดียวกัน กล่าวคือ ต้องเป็นข้อความธรรมดา เนื้อหา URI หรือIntent
ทั้งหมด และห้ามใช้ร่วมกัน -
เมื่อระบุข้อมูล คุณสามารถเสนอการแสดง MIME ที่แตกต่างกันได้ เพิ่มประเภท MIME
ที่คุณรองรับลงใน
ClipDescription
แล้วใช้ประเภท MIME ใน ผู้ให้บริการเนื้อหา -
เมื่อรับข้อมูลจากคลิปบอร์ด แอปพลิเคชันของคุณมีหน้าที่ตรวจสอบ
ประเภท MIME ที่ใช้ได้ แล้วตัดสินใจว่าจะใช้ประเภทใด (หากมี) แม้ว่าจะมีคลิปในคลิปบอร์ดและผู้ใช้ขอวาง แต่แอปพลิเคชันของคุณก็ไม่จำเป็นต้องวาง วางหากประเภท MIME เข้ากันได้ คุณอาจแปลงข้อมูล
ในคลิปบอร์ดเป็นข้อความโดยใช้
coerceToText()
หากแอปพลิเคชันรองรับ MIME ประเภทที่มีให้มากกว่า 1 ประเภท คุณสามารถให้ผู้ใช้เลือกประเภทที่จะใช้ได้