ผู้ใช้ชอบรูปภาพ วิดีโอ และเนื้อหาที่แสดงอารมณ์ชัดเจนอื่นๆ แต่การแทรกและ การย้ายเนื้อหานี้ ในแอปไม่ใช่เรื่องง่ายเสมอไป Android 12 (API ระดับ 31) เปิดตัว API แบบรวมที่ช่วยให้คุณรับเนื้อหาริชมีเดียจากแหล่งที่มาต่างๆ ได้ง่ายๆ ไม่ว่าจะเป็นคลิปบอร์ด คีย์บอร์ด หรือการลาก
คุณสามารถแนบอินเทอร์เฟซ เช่น OnReceiveContentListener
กับคอมโพเนนต์ UI และรับการเรียกกลับเมื่อมีการป้อนเนื้อหาผ่านกลไกใดก็ตาม การเรียกกลับจะเป็นที่เดียวสำหรับโค้ดของคุณในการจัดการการรับเนื้อหาทั้งหมด ตั้งแต่ข้อความธรรมดาและข้อความที่มีการจัดรูปแบบ ไปจนถึงมาร์กอัป รูปภาพ วิดีโอ ไฟล์เสียง และอื่นๆ
สำหรับความเข้ากันได้แบบย้อนหลังกับ Android เวอร์ชันก่อนหน้า API นี้ยัง มีให้บริการใน AndroidX ราคาเริ่มต้นที่ Core 1.7 และ Appcompat 1.4 ที่เราขอแนะนำให้คุณใช้เมื่อใช้ฟังก์ชันนี้
ภาพรวม
สำหรับ API อื่นๆ ที่มีอยู่ กลไก UI แต่ละอย่าง เช่น การแตะและ เมนูการระงับ หรือการลากจะมี API ที่เกี่ยวข้องของตัวเอง ซึ่งหมายความว่าคุณต้องผสานรวมกับ API แต่ละรายการแยกกัน โดยเพิ่มโค้ดที่คล้ายกันสำหรับกลไกแต่ละรายการที่แทรกเนื้อหา
OnReceiveContentListener
API จะรวมเส้นทางโค้ดต่างๆ เหล่านี้เข้าด้วยกันโดย
การสร้าง API เดียวสำหรับนำไปใช้
คุณจึงมุ่งเน้นที่ตรรกะเฉพาะของแอปได้
แล้วปล่อยให้แพลตฟอร์มจัดการส่วนที่เหลือให้
แนวทางนี้ยังหมายความว่าเมื่อมีการเพิ่มวิธีใหม่ในการแทรกเนื้อหาลงในแพลตฟอร์ม คุณไม่จําเป็นต้องทําการเปลี่ยนแปลงโค้ดเพิ่มเติมเพื่อเปิดใช้การรองรับในแอป และหากแอปของคุณต้องใช้การปรับแต่งทั้งหมดสําหรับ Use Case ที่เฉพาะเจาะจง คุณยังคงใช้ API ที่มีอยู่ได้ ซึ่งจะทํางานเหมือนเดิม
การใช้งาน
API เป็นอินเทอร์เฟซ Listener ที่มีเมธอดเดียว นั่นคือ OnReceiveContentListener
หากต้องการรองรับแพลตฟอร์ม Android เวอร์ชันเก่า เราขอแนะนำให้ใช้อินเทอร์เฟซ OnReceiveContentListener
ที่ตรงกันในไลบรารี AndroidX Core
หากต้องการใช้ API ให้ติดตั้งใช้งาน Listener โดยระบุประเภทเนื้อหาที่แอปของคุณจัดการได้ ดังนี้
object MyReceiver : OnReceiveContentListener { val MIME_TYPES = arrayOf("image/*", "video/*") // ... override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? { TODO("Not yet implemented") } }
public class MyReceiver implements OnReceiveContentListener { public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"}; // ... }
หลังจากระบุประเภท MIME ของเนื้อหาทั้งหมดที่แอปรองรับแล้ว ให้ติดตั้งใช้งานส่วนที่เหลือของโปรแกรมรับฟัง ดังนี้
class MyReceiver : OnReceiveContentListener { override fun onReceiveContent(view: View, contentInfo: ContentInfoCompat): ContentInfoCompat { val split = contentInfo.partition { item: ClipData.Item -> item.uri != null } val uriContent = split.first val remaining = split.second if (uriContent != null) { // App-specific logic to handle the URI(s) in uriContent. } // Return anything that your app didn't handle. This preserves the // default platform behavior for text and anything else that you aren't // implementing custom handling for. return remaining } companion object { val MIME_TYPES = arrayOf("image/*", "video/*") } }
public class MyReceiver implements OnReceiveContentListener { public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"}; @Override public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) { Pair<ContentInfoCompat, ContentInfoCompat> split = contentInfo.partition( item -> item.getUri() != null); ContentInfo uriContent = split.first; ContentInfo remaining = split.second; if (uriContent != null) { // App-specific logic to handle the URI(s) in uriContent. } // Return anything that your app didn't handle. This preserves the // default platform behavior for text and anything else that you aren't // implementing custom handling for. return remaining; } }
หากแอปรองรับการแชร์ด้วย Intent อยู่แล้ว คุณก็นําตรรกะเฉพาะแอปมาใช้จัดการ URI ของเนื้อหาซ้ำได้ แสดงผลข้อมูลที่เหลือเพื่อมอบสิทธิ์การจัดการข้อมูลดังกล่าวให้กับแพลตฟอร์ม
หลังจากใช้งาน Listener แล้ว ให้ตั้งค่าในองค์ประกอบ UI ที่เหมาะสมใน แอปของคุณ
class MyActivity : Activity() { public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... val myInput = findViewById(R.id.my_input) ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, MyReceiver()) } }
public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { // ... AppCompatEditText myInput = findViewById(R.id.my_input); ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, new MyReceiver()); } }
สิทธิ์ URI
แพลตฟอร์มจะให้สิทธิ์อ่านและเผยแพร่โดยอัตโนมัติสำหรับ
URI เนื้อหาในไฟล์
เพย์โหลดที่ส่งผ่านไปยัง OnReceiveContentListener
โดยปกติแล้ว แอปจะประมวลผล URI ของเนื้อหาในบริการหรือกิจกรรม สำหรับ
การประมวลผลเป็นเวลานาน ใช้
WorkManager เมื่อคุณใช้
ขยายสิทธิ์ไปยังบริการหรือกิจกรรมเป้าหมายโดยการส่ง
เนื้อหาที่ใช้
Intent.setClipData
และการตั้งค่าการตั้งค่าสถานะ
FLAG_GRANT_READ_URI_PERMISSION
หรือจะใช้เธรดพื้นหลังภายในบริบทปัจจุบันเพื่อประมวลผลเนื้อหาก็ได้ ในกรณีนี้ คุณต้องอ้างอิง
ออบเจ็กต์ payload
ที่ Listener ได้รับเพื่อช่วยตรวจสอบว่าไม่ได้มีสิทธิ์
แพลตฟอร์มถูกเพิกถอนก่อนกำหนด
มุมมองที่กำหนดเอง
หากแอปใช้คลาสย่อย View
ที่กำหนดเอง โปรดตรวจสอบว่า
ไม่ได้ข้าม OnReceiveContentListener
หากคลาส View
ลบล้างวิธี onCreateInputConnection
ให้ใช้ Jetpack API InputConnectionCompat.createWrapper
เพื่อกําหนดค่า InputConnection
หากคลาส View
ลบล้างเมธอด onTextContextMenuItem
ให้มอบสิทธิ์ให้กับ super เมื่อรายการเมนูเป็น R.id.paste
หรือ R.id.pasteAsPlainText
การเปรียบเทียบกับ API รูปภาพแป้นพิมพ์
คุณอาจมอง OnReceiveContentListener
API เป็น Keyboard Image API เวอร์ชันถัดไปที่มีอยู่ แบบรวมนี้
API สนับสนุนฟังก์ชันการทำงานของ API รูปภาพแป้นพิมพ์เช่นเดียวกับ
ฟีเจอร์เพิ่มเติม ความเข้ากันได้ของอุปกรณ์และฟีเจอร์จะแตกต่างกันไปขึ้นอยู่กับ
ไม่ว่าคุณจะใช้ไลบรารี Jetpack หรือ API เนทีฟจาก Android SDK
การดำเนินการหรือฟีเจอร์ | รองรับโดย API รูปภาพแป้นพิมพ์ | รองรับโดย API แบบรวม |
---|---|---|
แทรกจากแป้นพิมพ์ | มี (API ระดับ 13 ขึ้นไป) | ใช่ (API ระดับ 13 และสูงกว่า) |
แทรกโดยใช้การวางจากการแตะและ เมนูการระงับ | ไม่ | ใช่ |
แทรกโดยใช้การลากและวาง | ไม่ | ใช่ (API ระดับ 24 ขึ้นไป) |
การดำเนินการหรือฟีเจอร์ | รองรับโดย API รูปภาพแป้นพิมพ์ | รองรับโดย API แบบรวม |
---|---|---|
แทรกจากแป้นพิมพ์ | มี (API ระดับ 25 ขึ้นไป) | ใช่ (Android 12 ขึ้นไป) |
แทรกโดยใช้การวางจากการแตะและ เมนูการระงับ | ไม่ | |
แทรกโดยใช้การลากและวาง | ไม่ |