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

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

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

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

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

ภาพรวม

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

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

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

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

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

การใช้งาน

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

หากต้องการใช้ 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 ของเนื้อหาทั้งหมดที่แอปของคุณรองรับแล้ว ให้ใช้ส่วนที่เหลือของ Listener ดังนี้

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_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 เป็นคีย์บอร์ดเวอร์ชันถัดไป ของ API รูปภาพคีย์บอร์ดที่มีอยู่ API แบบรวมนี้รองรับฟังก์ชันการทำงานของ API รูปภาพแป้นพิมพ์ รวมถึงฟีเจอร์เพิ่มเติมบางอย่าง ความเข้ากันได้ของอุปกรณ์และฟีเจอร์จะแตกต่างกันไปตาม ว่าคุณใช้ไลบรารี Jetpack หรือ API ดั้งเดิมจาก Android SDK

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