Người dùng thích hình ảnh, video và những nội dung biểu đạt khác, nhưng chèn và việc di chuyển nội dung này trong các ứng dụng không phải lúc nào cũng dễ dàng. Để giúp các ứng dụng dễ dàng nhận nội dung đa dạng thức, Android 12 (API cấp 31) ra mắt một API hợp nhất cho phép ứng dụng của bạn chấp nhận nội dung từ mọi nguồn: bảng nhớ tạm, bàn phím hoặc kéo.
Bạn có thể đính kèm giao diện, chẳng hạn như
OnReceiveContentListener
!
vào các thành phần giao diện người dùng và nhận lệnh gọi lại khi nội dung được chèn thông qua bất kỳ
cơ chế. Lệnh gọi lại trở thành nơi duy nhất để mã của bạn xử lý việc nhận tất cả nội dung, từ văn bản thuần túy và có kiểu cho đến các dấu được đánh, hình ảnh, video, tệp âm thanh, v.v.
Để tương thích ngược với các phiên bản Android trước, API này cũng được có trong AndroidX, bắt đầu từ Core 1.7 và Appcompat 1.4, mà chúng tôi khuyên bạn nên sử dụng khi triển khai chức năng này.
Tổng quan
Với các API hiện có khác, mỗi cơ chế giao diện người dùng – chẳng hạn như thao tác chạm và giữ trình đơn hoặc kéo—có API tương ứng riêng. Điều này có nghĩa là bạn phải tích hợp riêng từng API, thêm mã tương tự cho từng cơ chế chèn nội dung:
API OnReceiveContentListener
hợp nhất các đường dẫn mã này bằng cách tạo một API duy nhất để triển khai, nhờ đó, bạn có thể tập trung vào logic riêng từng ứng dụng và để nền tảng xử lý phần còn lại:
Phương pháp này cũng có nghĩa là khi các phương pháp chèn nội dung mới được thêm vào nền tảng, bạn không cần phải thay đổi mã bổ sung để bật dịch vụ hỗ trợ trong ứng dụng của bạn. Nếu ứng dụng của bạn cần triển khai chế độ tuỳ chỉnh hoàn toàn cho một trường hợp sử dụng cụ thể, bạn vẫn có thể sử dụng các API hiện có, các API này vẫn hoạt động .
Triển khai
API là giao diện trình nghe có phương thức duy nhất là OnReceiveContentListener
.
Để hỗ trợ các phiên bản nền tảng Android cũ, bạn nên sử dụng giao diện OnReceiveContentListener
phù hợp trong thư viện AndroidX Core.
Để sử dụng API này, hãy triển khai trình nghe bằng cách chỉ định loại nội dung ứng dụng có thể xử lý:
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/*"}; // ... }
Sau khi chỉ định tất cả các loại MIME nội dung mà ứng dụng hỗ trợ, hãy triển khai phần còn lại của trình nghe:
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) { Pairsplit = 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; } }
Nếu ứng dụng của bạn đã hỗ trợ tính năng chia sẻ cùng với ý định, bạn có thể sử dụng lại logic dành riêng cho ứng dụng để xử lý URI nội dung. Trả về mọi dữ liệu còn lại để ủy quyền việc xử lý dữ liệu đó cho nền tảng.
Sau khi triển khai trình nghe, hãy đặt nó trên các thành phần trên giao diện người dùng thích hợp trong ứng dụng:
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()); } }
Quyền URI
Quyền đọc do nền tảng cấp và phát hành tự động đối với bất kỳ
URI nội dung trong
tải trọng được truyền đến OnReceiveContentListener
.
Thông thường, ứng dụng của bạn sẽ xử lý URI nội dung trong một dịch vụ hoặc hoạt động. Cho
xử lý lâu dài, sử dụng
WorkManager. Khi bạn triển khai
này, mở rộng quyền sang dịch vụ hoặc hoạt động mục tiêu bằng cách truyền
nội dung sử dụng
Intent.setClipData
và đặt cờ
FLAG_GRANT_READ_URI_PERMISSION
.
Ngoài ra, bạn có thể sử dụng chuỗi (thread) nền trong ngữ cảnh hiện tại để xử lý nội dung. Trong trường hợp này, bạn phải duy trì tham chiếu đến
payload
mà trình nghe nhận được để giúp đảm bảo rằng các quyền không
bị nền tảng thu hồi sớm.
Chế độ xem tùy chỉnh
Nếu ứng dụng của bạn dùng một lớp con View
tuỳ chỉnh, hãy chú ý đảm bảo rằng
Chưa bỏ qua OnReceiveContentListener
.
Nếu lớp View
ghi đè phương thức onCreateInputConnection
, hãy sử dụng Jetpack API InputConnectionCompat.createWrapper
để định cấu hình InputConnection
.
Nếu lớp View
của bạn ghi đè lớp
onTextContextMenuItem
, uỷ quyền cho siêu dữ liệu khi mục trong trình đơn là
R.id.paste
hoặc
R.id.pasteAsPlainText
.
So sánh với API hình ảnh bàn phím
Bạn có thể coi API OnReceiveContentListener
là phiên bản tiếp theo của API hình ảnh bàn phím hiện có. API thống nhất này hỗ trợ chức năng của API hình ảnh bàn phím cũng như một số tính năng bổ sung. Khả năng tương thích của thiết bị và tính năng sẽ thay đổi tùy thuộc vào việc bạn sử dụng thư viện Jetpack hoặc API gốc từ SDK Android.
Hành động hoặc tính năng | Được hỗ trợ bởi API hình ảnh bàn phím | Được API hợp nhất hỗ trợ |
---|---|---|
Chèn từ bàn phím | Có (API cấp 13 trở lên) | Có (API cấp 13 trở lên) |
Chèn bằng cách dán từ thao tác chạm & giữ trình đơn | Không | Có |
Chèn bằng thao tác kéo và thả | Không | Có (API cấp 24 trở lên) |
Hành động hoặc tính năng | Được hỗ trợ bởi API hình ảnh bàn phím | Được API hợp nhất hỗ trợ |
---|---|---|
Chèn từ bàn phím | Có (API cấp 25 trở lên) | Có (Android 12 trở lên) |
Chèn bằng cách dán từ thao tác chạm & giữ trình đơn | Không | |
Chèn bằng cách kéo và thả | Không |