Android มีเฟรมเวิร์กแบบคลิปบอร์ดที่มีประสิทธิภาพสำหรับการคัดลอกและวาง รองรับ และประเภทข้อมูลที่ซับซ้อน เช่น สตริงข้อความ โครงสร้างข้อมูลที่ซับซ้อน ข้อความและสตรีมไบนารี และข้อมูลแอปพลิเคชัน ข้อมูลข้อความธรรมดาจะเก็บไว้ในคลิปบอร์ดโดยตรงในขณะที่มีความซับซ้อน ข้อมูลจะจัดเก็บเป็นข้อมูลอ้างอิงที่แอปพลิเคชันการวางจะแก้ปัญหากับผู้ให้บริการเนื้อหา กำลังคัดลอก และการวางจะทำงานทั้งภายในแอปพลิเคชันและระหว่างแอปพลิเคชันที่ใช้
เนื่องจากส่วนหนึ่งของกรอบการทำงานใช้ผู้ให้บริการเนื้อหา เอกสารนี้จึงอนุมานว่าคุ้นเคยกับ Android Content Provider API ซึ่งอธิบายไว้ใน ผู้ให้บริการเนื้อหา
ผู้ใช้คาดหวังความคิดเห็นเมื่อคัดลอกเนื้อหาไปยังคลิปบอร์ด ดังนั้น นอกเหนือจากกรอบการทำงานที่ ขับเคลื่อนการคัดลอกและวาง Android จะแสดง UI เริ่มต้นแก่ผู้ใช้เมื่อคัดลอกใน Android 13 (API ระดับ 33) และสูงกว่า และเนื่องจากฟีเจอร์นี้ จึงมีความเสี่ยงที่จะมีการแจ้งเตือนซ้ำ คุณสามารถดูข้อมูลเพิ่มเติมเกี่ยวกับ เคสขอบนี้จะอยู่ใน หลีกเลี่ยงการแจ้งเตือนซ้ำ
แสดงความคิดเห็นแก่ผู้ใช้ด้วยตนเองเมื่อคัดลอกใน Android 12L (API ระดับ 32) และต่ำกว่า โปรดดู คำแนะนำสำหรับเรื่องนี้ในเอกสารนี้
เฟรมเวิร์กคลิปบอร์ด
เมื่อใช้เฟรมเวิร์กคลิปบอร์ด ให้นำข้อมูลไปไว้ในออบเจ็กต์คลิป แล้ววางออบเจ็กต์คลิป บนคลิปบอร์ดของทั้งระบบ ออบเจ็กต์คลิปอาจมี 1 ใน 3 รูปแบบต่อไปนี้
- ข้อความ
- สตริงข้อความ ใส่สตริงลงในออบเจ็กต์คลิปโดยตรง แล้วนำไปวางใน คลิปบอร์ด หากต้องการวางสตริง ให้เอาออบเจ็กต์คลิปจากคลิปบอร์ดแล้วคัดลอก ลงในพื้นที่เก็บข้อมูลของแอปพลิเคชัน
- URI
-
ออบเจ็กต์
Uri
ที่แสดงถึงค่าใดๆ รูปแบบ URI ส่วนนี้ใช้สำหรับการคัดลอกข้อมูลที่ซับซ้อนจากผู้ให้บริการเนื้อหาเป็นหลัก เพื่อคัดลอก ให้นำออบเจ็กต์Uri
ไปไว้ในออบเจ็กต์คลิป แล้ววางออบเจ็กต์คลิปลงใน คลิปบอร์ด หากต้องการวางข้อมูล ให้รับออบเจ็กต์คลิป รับออบเจ็กต์Uri
แปลงเป็นแหล่งข้อมูล เช่น ผู้ให้บริการเนื้อหา และคัดลอกข้อมูลจาก ลงในพื้นที่เก็บข้อมูลของแอปพลิเคชัน - ความตั้งใจ
-
Intent
ช่วงเวลานี้ รองรับการคัดลอกทางลัดไปยังแอปพลิเคชัน หากต้องการคัดลอกข้อมูล ให้สร้างIntent
ป้อน ไว้ในออบเจ็กต์คลิป แล้ววางออบเจ็กต์คลิปไว้บนคลิปบอร์ด หากต้องการวางข้อมูล ให้เรียก ออบเจ็กต์คลิป แล้วคัดลอกออบเจ็กต์Intent
ไปยัง พื้นที่หน่วยความจำ
คลิปบอร์ดจะเก็บออบเจ็กต์คลิปได้ครั้งละ 1 รายการเท่านั้น เมื่อแอปพลิเคชันวางวัตถุคลิปบน คลิปบอร์ด ออบเจ็กต์คลิปก่อนหน้าจะหายไป
ถ้าต้องการให้ผู้ใช้วางข้อมูลลงในแอปพลิเคชันของคุณ คุณไม่จำเป็นต้องจัดการทุกประเภท คุณตรวจสอบข้อมูลในคลิปบอร์ดได้ก่อนให้ผู้ใช้เลือกวางข้อมูลได้ นอกจากจะมีแบบฟอร์มข้อมูลบางอย่างแล้ว ออบเจ็กต์คลิปยังมีข้อมูลเมตาที่บอกคุณว่า MIME ใด ประเภทต่างๆ ได้ ข้อมูลเมตานี้ช่วยให้คุณตัดสินใจได้ว่าแอปพลิเคชันของคุณมีประโยชน์อะไรบ้าง ด้วยข้อมูลคลิปบอร์ด ตัวอย่างเช่น หากคุณมีแอปพลิเคชันที่ทำงานกับข้อความเป็นหลัก คุณ คุณอาจต้องละเว้นออบเจ็กต์คลิปที่มี URI หรือ Intent
นอกจากนี้ คุณอาจต้องให้ผู้ใช้วางข้อความไม่ว่าข้อมูลในคลิปบอร์ดจะเป็นรูปแบบใดก็ตาม ถึง ให้บังคับข้อมูลในคลิปบอร์ดเป็นข้อความ แล้ววางข้อความนี้ นี่คือ ตามที่อธิบายไว้ในส่วนบังคับคลิปบอร์ดเป็นข้อความ
คลาสคลิปบอร์ด
ส่วนนี้จะอธิบายคลาสที่เฟรมเวิร์กคลิปบอร์ดใช้
เครื่องมือจัดการคลิปบอร์ด
คลิปบอร์ดของระบบ Android แสดงโดยผู้คนทั่วโลก
ClipboardManager
ชั้นเรียน
อย่าสร้างอินสแตนซ์ชั้นเรียนนี้โดยตรง แต่ให้รับการอ้างอิงด้วยการเรียกใช้
getSystemService(CLIPBOARD_SERVICE)
ClipData, ClipData.Item และ ClipDescription
หากต้องการเพิ่มข้อมูลลงในคลิปบอร์ด ให้สร้าง
ClipData
ออบเจ็กต์ที่มี
คำอธิบายของข้อมูลและตัวข้อมูล คลิปบอร์ดเก็บ ClipData
ไว้ 1 รายการที่
ClipData
มี
ออบเจ็กต์ ClipDescription
รายการ
และอย่างน้อย 1 รายการ
ออบเจ็กต์ ClipData.Item
รายการ
ออบเจ็กต์ ClipDescription
มีข้อมูลเมตาเกี่ยวกับคลิป ยิ่งไปกว่านั้น
มีอาร์เรย์ของประเภท MIME ที่ใช้ได้กับข้อมูลของคลิป นอกจากนี้ ให้เปิด
Android 12 (API ระดับ 31) ขึ้นไป ข้อมูลเมตาจะมีข้อมูลเกี่ยวกับว่าออบเจ็กต์
ประกอบด้วย
ข้อความที่ทำสไตไลซ์และเกี่ยวกับ
ประเภทของข้อความในออบเจ็กต์
เมื่อคุณวางคลิปในคลิปบอร์ด ข้อมูลนี้จะพร้อมใช้สำหรับการวางแอปพลิเคชัน ซึ่ง
จะตรวจสอบว่าตนจัดการข้อมูลคลิปได้หรือไม่
ออบเจ็กต์ ClipData.Item
มีข้อความ, URI หรือ Intent ดังนี้
- ข้อความ
-
CharSequence
- URI
-
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 ที่มีอยู่จาก Content Provider แล้วจัดเก็บไว้ในClipDescription
สำหรับ URI ที่ไม่ใช่ URIcontent:
โดยเมธอดจะกำหนดประเภท MIME เป็นMIMETYPE_TEXT_URILIST
ใช้
newUri()
เพื่อสร้างคลิปจาก URI โดยเฉพาะอย่างยิ่ง URIcontent:
-
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()
ไม่เป็นค่าว่าง—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 รายการและอย่างน้อย 1 รายการ
ออบเจ็กต์ ClipDescription
รายการ แอปพลิเคชันจะได้รับ ClipData
เพื่อวางข้อมูล
รับประเภท MIME จาก ClipDescription
และรับข้อมูลจาก
ClipData.Item
หรือจากผู้ให้บริการเนื้อหาที่กล่าวถึงโดย
ClipData.Item
คัดลอกไปยังคลิปบอร์ด
หากต้องการคัดลอกข้อมูลไปยังคลิปบอร์ด ให้ใช้แฮนเดิลของออบเจ็กต์ ClipboardManager
ส่วนกลาง
สร้างออบเจ็กต์ ClipData
และเพิ่ม ClipDescription
และอีกอย่างน้อย 1 รายการ
ClipData.Item
ออบเจ็กต์ จากนั้นเพิ่มออบเจ็กต์ 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
ข้อมูลโค้ดนี้จะสร้าง
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() }
เพิ่มเนื้อหาที่ละเอียดอ่อนลงในคลิปบอร์ด
หากแอปของคุณอนุญาตให้ผู้ใช้คัดลอกเนื้อหาที่ละเอียดอ่อนไปยังคลิปบอร์ด เช่น รหัสผ่านหรือเครดิต
ข้อมูลบัตร คุณต้องเพิ่มธงไปยัง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
และเรียกเนื้อหาที่เหมาะสม
ในการเรียกดูข้อมูล
ขั้นตอนต่อไปนี้อธิบายวิธีรับข้อมูลจากผู้ให้บริการเนื้อหาโดยอิงตาม 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(); } } } }
วางความตั้งใจ
หากต้องการวางความตั้งใจ ให้เริ่มจากคลิปบอร์ดส่วนกลาง ตรวจสอบออบเจ็กต์ ClipData.Item
เพื่อดูว่ามี Intent
หรือไม่ จากนั้นโทรหา getIntent()
เพื่อคัดลอก
พื้นที่เก็บข้อมูลของคุณเอง ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นสิ่งต่อไปนี้
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) ขึ้นไป โดยปกติระบบจะแสดงข้อความโทสต์เมื่อแอปของคุณ
การโทร
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 รูปแบบ - หากแอปพลิเคชันของคุณมีฐานข้อมูลภายใน คุณอาจต้องย้ายฐานข้อมูลนี้ เป็นผู้ให้บริการเนื้อหาเพื่ออำนวยความสะดวกในการคัดลอก
- หากคุณไม่ได้ใช้ฐานข้อมูล คุณสามารถใช้ผู้ให้บริการเนื้อหาแบบง่ายที่ จุดประสงค์เดียวคือการนำเสนอข้อมูลให้กับแอปพลิเคชันที่วางจากคลิปบอร์ด
ในผู้ให้บริการเนื้อหา ให้ลบล้างเมธอดต่อไปนี้เป็นอย่างน้อย
-
query()
- การวางแอปพลิเคชันจะถือว่าแอปได้รับข้อมูลของคุณเมื่อใช้วิธีการนี้กับ URI ที่คุณตั้ง ไว้ในคลิปบอร์ด เพื่อรองรับการคัดลอก ให้วิธีนี้ตรวจหา URI ที่มี "คัดลอก" เส้นทาง จากนั้น แอปพลิเคชันของคุณสามารถสร้าง "สำเนา" ได้ 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
ที่สอดคล้องกับสตริง
"ข้อบ่งชี้" ต่อท้ายชื่อเมธอด ตัวอย่างเช่น ContentResolver
แอนะล็อกของ
วันที่ openAssetFile()
เท่ากับ
openAssetFileDescriptor()
-
openTypedAssetFile()
-
เมธอดนี้จะแสดงข้อบ่งชี้ไฟล์เนื้อหา แต่เฉพาะในกรณีที่ประเภท MIME ที่ระบุคือ ที่ผู้ให้บริการรองรับ ผู้โทรซึ่งเป็นแอปพลิเคชันที่กำลังวางข้อมูลจะให้ รูปแบบประเภท MIME ผู้ให้บริการเนื้อหาของแอปพลิเคชันที่คัดลอก URI ไปยังฟังก์ชัน คลิปบอร์ดจะแสดงแฮนเดิลไฟล์
AssetFileDescriptor
หากสามารถระบุได้ ประเภท MIME และแสดงข้อผิดพลาดหากทำไม่ได้วิธีนี้จะจัดการส่วนย่อยของไฟล์ คุณสามารถใช้รายงานนี้เพื่ออ่านเนื้อหาที่ ผู้ให้บริการเนื้อหาได้คัดลอกไปยังคลิปบอร์ดแล้ว
-
openAssetFile()
-
วิธีนี้เป็นรูปแบบทั่วไปของ
openTypedAssetFile()
ไม่ได้กรอง สำหรับประเภท MIME ที่อนุญาต แต่สามารถอ่านส่วนย่อยของไฟล์ได้ -
openFile()
-
นี่คือรูปแบบที่กว้างขึ้นของ
openAssetFile()
ไม่สามารถอ่านส่วนย่อยของ
คุณสามารถเลือกใช้
openPipeHelper()
กับเมธอดข้อบ่งชี้ไฟล์ ซึ่งช่วยให้แอปพลิเคชันการวางสามารถอ่านข้อมูลสตรีมใน
เทรดพื้นหลังโดยใช้ไปป์ หากต้องการใช้วิธีนี้ ให้ใช้เมธอด
ContentProvider.PipeDataWriter
ของ Google
ออกแบบฟังก์ชันการคัดลอกและวางที่มีประสิทธิภาพ
ในการออกแบบฟังก์ชันคัดลอกและวางที่มีประสิทธิภาพสำหรับแอปพลิเคชันของคุณ ให้จดจำประเด็นเหล่านี้:
- ในแต่ละครั้งจะมีคลิปเพียงคลิปเดียวในคลิปบอร์ด คัดลอกใหม่โดย แอปพลิเคชันในระบบจะแทนที่คลิปก่อนหน้า เนื่องจากผู้ใช้อาจไปยังส่วนต่างๆ ออกจากแอปพลิเคชันและคัดลอกก่อนส่งคืน คุณจะยึดคลิปบอร์ดไม่ได้ มีคลิปที่ผู้ใช้คัดลอกไว้ก่อนหน้านี้ในแอปพลิเคชันของคุณ
-
วัตถุประสงค์ของออบเจ็กต์
ClipData.Item
หลายรายการต่อคลิปคือการ สนับสนุนการคัดลอกและวางรายการที่เลือกหลายรายการ แทนที่จะเป็นรูปแบบที่แตกต่างกัน อ้างอิงถึงตัวเลือกเดียวก็ได้ ปกติแล้วคุณจะต้องการClipData.Item
ทั้งหมด ในคลิปเพื่อให้อยู่ในรูปแบบเดียวกัน กล่าวคือ ทั้งหมดจะต้องเป็นข้อความธรรมดา เนื้อหา URI หรือIntent
และไม่ผสม -
เมื่อคุณให้ข้อมูล คุณสามารถเสนอการนำเสนอ MIME ที่แตกต่างกันได้ เพิ่มประเภท MIME
ที่คุณรองรับ
ClipDescription
แล้วใช้ประเภท MIME ใน ผู้ให้บริการเนื้อหาของคุณ -
เมื่อดึงข้อมูลจากคลิปบอร์ด แอปพลิเคชันของคุณจะทำหน้าที่ตรวจสอบ
ประเภท MIME ที่มีอยู่ แล้วจึงค่อยตัดสินใจว่าจะใช้ MIME ประเภทใด (หากมี) แม้ว่าจะมี
คลิปบนคลิปบอร์ดและผู้ใช้ขอให้วาง แอปพลิเคชันของคุณจึงไม่จำเป็น
เพื่อวางได้ วางหากประเภท MIME เข้ากันได้ คุณอาจบังคับข้อมูล
บนคลิปบอร์ดเพื่อส่งข้อความโดยใช้
coerceToText()
หากแอปพลิเคชันของคุณรองรับ ประเภท MIME ที่มีอยู่มากกว่า 1 ประเภท คุณสามารถให้ผู้ใช้เลือกประเภทที่ต้องการได้