รับเนื้อหาอย่างละเอียด

รูปที่ 1 API แบบรวมเป็นแพลตฟอร์มเดียวที่ใช้จัดการเนื้อหาขาเข้าได้ ไม่ว่าจะใช้กลไก UI แบบใด เช่น การวางจากเมนูแตะค้างไว้หรือใช้การลากและวาง

ผู้ใช้ชอบรูปภาพ วิดีโอ และเนื้อหาสื่ออารมณ์อื่นๆ แต่การแทรกและย้ายเนื้อหานี้ในแอปก็ไม่ใช่เรื่องง่ายเสมอไป เพื่อให้แอปรับเนื้อหาที่เป็นสื่อสมบูรณ์ได้ง่ายขึ้น Android 12 (API ระดับ 31) เปิดตัว API แบบรวมที่ช่วยให้แอปยอมรับเนื้อหาจากแหล่งที่มาใดก็ได้ เช่น คลิปบอร์ด แป้นพิมพ์ หรือการลาก

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

API นี้ยังพร้อมใช้งานใน AndroidX อีกด้วย เพื่อช่วยในการรองรับการทำงานร่วมกับ Android เวอร์ชันเก่าๆ โดยเริ่มตั้งแต่ Core 1.7 และ Appcompat 1.4 ซึ่งเราขอแนะนำให้คุณใช้เมื่อติดตั้งใช้งานฟังก์ชันนี้

ภาพรวม

สำหรับ API อื่นๆ ที่มีอยู่ กลไก UI แต่ละอย่าง เช่น เมนูการแตะค้างไว้หรือการลากจะมี API ที่สอดคล้องกัน ซึ่งหมายความว่าคุณต้องผสานรวมกับ API แต่ละรายการแยกกัน โดยเพิ่มโค้ดที่คล้ายกันสำหรับกลไกแต่ละรายการที่แทรกเนื้อหา

รูปภาพแสดงการดำเนินการต่างๆ และ API ที่เกี่ยวข้องเพื่อใช้งาน
รูปที่ 2 ก่อนหน้านี้ แอปใช้ API ที่แตกต่างกันสำหรับกลไกการแทรกเนื้อหา UI แต่ละรายการ

OnReceiveContentListener API จะรวมเส้นทางโค้ดต่างๆ เหล่านี้เข้าด้วยกันโดยการสร้าง API รายการเดียวเพื่อใช้งาน คุณจึงมุ่งเน้นที่ตรรกะเฉพาะแอปได้และปล่อยให้แพลตฟอร์มจัดการส่วนที่เหลือ

รูปภาพแสดง Unified API ที่เข้าใจง่าย
รูปที่ 3 API แบบรวมช่วยให้คุณใช้ API เดียวที่รองรับกลไก UI ทั้งหมดได้

แนวทางนี้ยังหมายความว่าเมื่อมีการเพิ่มวิธีใหม่ๆ ในการแทรกเนื้อหาลงในแพลตฟอร์ม คุณไม่จำเป็นต้องเปลี่ยนแปลงโค้ดเพิ่มเติมเพื่อเปิดใช้การสนับสนุนในแอป และหากแอปต้องใช้การปรับแต่งเต็มรูปแบบสำหรับกรณีการใช้งานหนึ่งโดยเฉพาะ คุณยังคงใช้ API ที่มีอยู่ซึ่งจะทำงานได้เหมือนเดิม

การใช้งาน

API เป็นอินเทอร์เฟซ Listener ที่มีเมธอดเดียว นั่นคือ OnReceiveContentListener หากต้องการรองรับแพลตฟอร์ม Android เวอร์ชันเก่า เราขอแนะนำให้ใช้อินเทอร์เฟซ OnReceiveContentListener ที่ตรงกันในไลบรารี AndroidX Core

หากต้องการใช้ API ให้ติดตั้งใช้งาน Listener โดยระบุประเภทเนื้อหาที่แอปของคุณจัดการได้ ดังนี้

Kotlin

object MyReceiver : OnReceiveContentListener {
    val MIME_TYPES = arrayOf("image/*", "video/*")
    
    // ...
    
    override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
        TODO("Not yet implemented")
    }
}

Java

public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};
     // ...
}

หลังจากระบุประเภท MIME ของเนื้อหาทั้งหมดที่แอปรองรับแล้ว ให้ติดตั้งใช้งานโปรแกรมฟังที่เหลือ ดังนี้

Kotlin

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/*")
    }
}

Java

 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 ที่เหมาะสมในแอป ดังนี้

Kotlin

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())
    }
}

Java

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 FLAG_GRANT_READ_URI_PERMISSION

หรือจะใช้เธรดพื้นหลังภายในบริบทปัจจุบันเพื่อประมวลผลเนื้อหาก็ได้ ในกรณีนี้ คุณต้องเก็บการอ้างอิงไปยังออบเจ็กต์ payload ที่ผู้ฟังได้รับไว้เพื่อให้มั่นใจว่าแพลตฟอร์มจะไม่เพิกถอนสิทธิ์ก่อนเวลาอันควร

มุมมองที่กำหนดเอง

หากแอปใช้คลาสย่อย View ที่กำหนดเอง โปรดตรวจสอบว่าไม่มีการข้าม OnReceiveContentListener

หากคลาส View ลบล้างเมธอด onCreateInputConnection ให้ใช้ Jetpack API InputConnectionCompat.createWrapper เพื่อกำหนดค่า InputConnection

หากคลาส View ลบล้างเมธอด onTextContextMenuItem ให้มอบสิทธิ์ขั้นสูงเมื่อรายการในเมนูคือ R.id.paste หรือ R.id.pasteAsPlainText

การเปรียบเทียบกับ API รูปภาพแป้นพิมพ์

คุณอาจมอง OnReceiveContentListener API เป็น Keyboard Image API เวอร์ชันถัดไปที่มีอยู่ API แบบรวมนี้รองรับฟังก์ชันการทำงานของ API รูปภาพแป้นพิมพ์ รวมถึงฟีเจอร์เพิ่มเติมบางอย่าง ความเข้ากันได้ของอุปกรณ์และฟีเจอร์จะแตกต่างกันไป ขึ้นอยู่กับว่าคุณใช้ไลบรารี Jetpack หรือ API แบบเนทีฟจาก Android SDK

ตารางที่ 1 ฟีเจอร์และระดับ API ที่รองรับสำหรับ Jetpack
การดำเนินการหรือฟีเจอร์ รองรับโดย API รูปภาพแป้นพิมพ์ รองรับโดย Unified API
แทรกจากแป้นพิมพ์ ใช่ (API ระดับ 13 ขึ้นไป) ใช่ (API ระดับ 13 ขึ้นไป)
แทรกโดยใช้การวางจากเมนูการแตะค้างไว้ ไม่ ใช่
แทรกโดยใช้การลากและวาง ไม่ ใช่ (API ระดับ 24 ขึ้นไป)
ตารางที่ 2 ฟีเจอร์และระดับ API ที่รองรับสําหรับ API เดิม
การดำเนินการหรือฟีเจอร์ รองรับโดย API รูปภาพแป้นพิมพ์ รองรับโดย Unified API
แทรกจากแป้นพิมพ์ ใช่ (API ระดับ 25 ขึ้นไป) ใช่ (Android 12 ขึ้นไป)
แทรกโดยใช้การวางจากเมนูการแตะค้างไว้ ไม่
แทรกโดยใช้การลากและวาง ไม่