Nhận dữ liệu từ các ứng dụng khác

Giống như một ứng dụng có thể gửi dữ liệu đến các ứng dụng khác, ứng dụng đó cũng có thể nhận dữ liệu từ các ứng dụng khác. Hãy nghĩ về cách người dùng tương tác với ứng dụng của bạn và những loại dữ liệu mà bạn muốn nhận từ các ứng dụng khác. Ví dụ: một ứng dụng mạng xã hội có thể quan tâm đến việc nhận nội dung văn bản (chẳng hạn như một URL cho web thú vị) từ một ứng dụng khác.

Trong một ứng dụng sử dụng tính năng Điều hướng trong Compose, việc nhận dữ liệu do một ứng dụng khác gửi là một quy trình gồm 3 bước:

  1. Khai báo <intent-filter> trong tệp kê khai: Bạn vẫn phải thêm bộ lọc ý định vào hoạt động trong tệp AndroidManifest.xml. Điều này cho hệ điều hành Android biết rằng ứng dụng của bạn có thể nhận các thao tác cụ thể (như ACTION_SEND) và loại MIME (như text/plain).

  2. Xác định navDeepLink trong biểu đồ Điều hướng trong Compose: Đính kèm navDeepLink khớp với thao tác và loại MIME trực tiếp vào đích đến thành phần kết hợp sẽ hiển thị nội dung. NavController sẽ tự động chặn ý định đến và chuyển hướng người dùng trực tiếp đến màn hình đó.

  3. Trích xuất tải trọng dữ liệu đến: Trong màn hình đích đến, hãy truy cập vào các ý định bổ sung (chẳng hạn như EXTRA_TEXT hoặc EXTRA_STREAM) để truy xuất nội dung được chia sẻ và cập nhật trạng thái giao diện người dùng.

Mục tiêu Chia sẻ trực tiếp là các đường liên kết sâu đến một hoạt động cụ thể trong ứng dụng của bạn. Các đường liên kết này thường đại diện cho một người hoặc một nhóm và được hiển thị trong Trang chia sẻ của Android. Ví dụ: một ứng dụng nhắn tin có thể cung cấp mục tiêu Chia sẻ trực tiếp cho một người liên kết sâu trực tiếp vào cuộc trò chuyện với người đó. Hãy xem bài viết Cung cấp mục tiêu Chia sẻ trực tiếp để biết hướng dẫn chi tiết.

Hỗ trợ loại MIME

Tốt nhất là một ứng dụng phải có thể nhận được nhiều loại MIME nhất có thể. Ví dụ: một ứng dụng nhắn tin được thiết kế để gửi văn bản, hình ảnh và video lý tưởng nhất là hỗ trợ nhận text/*, image/* và video/*. Dưới đây là một số loại MIME phổ biến để gửi và nhận dữ liệu trong Android.

Trình nhận đăng ký Trình gửi gửi
text/*
  • text/plain
  • text/rtf
  • text/html
  • text/json
image/*
  • image/jpg
  • image/png
  • image/gif
video/*
  • video/mp4
  • video/3gp
Đuôi tệp được hỗ trợ application/pdf

Xem sổ đăng ký chính thức của IANA về các loại nội dung nghe nhìn MIME.

Tạo mục tiêu chia sẻ tuyệt vời

Khi người dùng nhấn vào một mục tiêu chia sẻ được liên kết với một hoạt động cụ thể, hãy cho phép họ xác nhận và chỉnh sửa nội dung được chia sẻ trước khi ứng dụng của bạn sử dụng nội dung đó. Điều này đặc biệt quan trọng đối với dữ liệu văn bản.

Nhận dữ liệu trong ứng dụng

Việc nhận dữ liệu được chia sẻ trong một ứng dụng sử dụng Compose bao gồm việc khai báo bộ lọc ý định trong tệp kê khai, chuyển ý định đến đến màn hình thích hợp bằng đường liên kết sâu và trích xuất tải trọng từ ý định để cập nhật giao diện người dùng.

Cập nhật tệp kê khai

Bộ lọc ý định thông báo cho hệ thống biết những ý định mà một thành phần ứng dụng chấp nhận. Tương tự như cách bạn tạo một ý định bằng thao tác ACTION_SEND trong bài học Gửi dữ liệu đến các ứng dụng khác, bạn sẽ tạo bộ lọc ý định để nhận ý định bằng thao tác này. Bạn xác định bộ lọc ý định trong tệp kê khai bằng phần tử <intent-filter>. Ví dụ: nếu ứng dụng của bạn xử lý việc nhận nội dung văn bản, thì tệp kê khai bao gồm một hoặc nhiều hình ảnh thuộc bất kỳ loại nào sẽ có dạng như đoạn mã sau:

<activity android:name=".ui.MyActivity" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND_MULTIPLE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
</activity>

Khi một ứng dụng khác cố gắng chia sẻ bất kỳ nội dung nào trong số này bằng cách tạo một ý định và truyền ý định đó đến startActivity(), ứng dụng của bạn sẽ được liệt kê là một lựa chọn trong Trang chia sẻ nội dung trong Android hoặc trình phân giải ý định. Nếu người dùng chọn ứng dụng của bạn, thì thao tác này sẽ bắt đầu hoạt động tương ứng (.ui.MyActivity trong ví dụ trước). Sau đó, bạn sẽ phải xử lý nội dung một cách thích hợp trong mã và giao diện người dùng.

Trong tính năng Điều hướng trong Compose, hãy đính kèm navDeepLink trực tiếp vào đích đến thành phần kết hợp sẽ hiển thị nội dung. Khi một ứng dụng khác chia sẻ dữ liệu khớp với bộ lọc ý định của bạn, tính năng Điều hướng trong Compose sẽ chuyển hướng người dùng trực tiếp đến đích đến này:

navDeepLink khớp với thao tác và loại MIME của ý định đến để chuyển đến màn hình đích đến chính xác. Sau khi đến đích đến đó, trình xử lý sẽ kiểm tra ý định để xác định tải trọng nào đã nhận được (chẳng hạn như một hình ảnh so với nhiều hình ảnh) và trích xuất các ý định bổ sung tương ứng.

Xử lý nội dung đến

Để truy xuất nội dung do Intent cung cấp, hãy đọc hoạt động hiện tại từ LocalActivity.current trong thành phần kết hợp, sau đó kiểm tra ý định để xác định việc cần làm tiếp theo. Nếu hoạt động này có thể bắt đầu từ các phần khác của hệ thống (chẳng hạn như trình chạy), hãy cân nhắc điều này khi kiểm tra ý định.

Hãy đặc biệt cẩn thận để kiểm tra dữ liệu đến: loại MIME có thể được đặt không chính xác hoặc hình ảnh được gửi có thể cực kỳ lớn. Xử lý dữ liệu nhị phân hoặc các thao tác I/O nặng (chẳng hạn như giải mã hình ảnh lớn hoặc ghi tệp) không đồng bộ bằng cách sử dụng coroutine (chẳng hạn như Dispatchers.IO) thay vì trên luồng giao diện người dùng chính.

@Composable
fun SharesheetHandler() {
    val activity = LocalActivity.current
    val intent = activity?.intent

    when (intent?.action) {
        Intent.ACTION_SEND -> {
            if (intent.type == "text/plain") {
                handleSendText(intent) // Handle text being sent
            } else if (intent.type?.startsWith("image/") == true) {
                handleSendImage(intent) // Handle single image being sent
            }
        }

        Intent.ACTION_SEND_MULTIPLE -> {
            if (intent.type?.startsWith("image/") == true) {
                handleSendMultipleImages(intent) // Handle multiple images being sent
            }
        }

        else -> {
            // Handle other intents, such as being started from the home screen
        }
    }
}

private fun handleSendText(intent: Intent) {
    intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
        // Update UI state with the shared text
    }
}

private fun handleSendImage(intent: Intent) {
    val imageUri = IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java)
    imageUri?.let {
        // Update UI state with the shared image
    }
}

private fun handleSendMultipleImages(intent: Intent) {
    val imageUris =
        IntentCompat.getParcelableArrayListExtra(intent, Intent.EXTRA_STREAM, Uri::class.java)
    imageUris?.let {
        // Update UI state with the shared images
    }
}

Khi trích xuất dữ liệu nhị phân hoặc URI từ các ý định bổ sung (chẳng hạn như EXTRA_STREAM), hãy sử dụng IntentCompat.getParcelableExtra() hoặc IntentCompat.getParcelableArrayListExtra() từ thư viện AndroidX Core, như minh hoạ trong các hàm handleSendImage và handleSendMultipleImages trước đó. Android 13 (cấp độ API 33) không dùng phương thức Intent.getParcelableExtra(String) không tham số nữa mà dùng các phương thức an toàn về kiểu lấy loại lớp dự kiến.

Việc cập nhật giao diện người dùng sau khi nhận dữ liệu có thể đơn giản như cập nhật trạng thái để điền vào TextField hoặc phức tạp như áp dụng bộ lọc cho hình ảnh. Ứng dụng của bạn sẽ quyết định việc cần làm tiếp theo.

Chia sẻ URL ảnh chụp màn hình

Khi chụp ảnh màn hình, bạn có thể chia sẻ ảnh chụp màn hình và mọi URL được liên kết. Điều này mang lại trải nghiệm phong phú hơn cho người dùng. Khi nhận URL, hãy nhớ lấy trường EXTRA_TEXT từ ý định, như minh hoạ trong ví dụ sau:

IntentCompat.getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri::class.java).let {
    // Handle the EXTRA_TEXT as well
    val extraText = intent.getCharSequenceExtra(Intent.EXTRA_TEXT)
    // Update UI state with the shared image and the EXTRA_TEXT if available
}

Đảm bảo người dùng nhận ra ứng dụng của bạn

Ứng dụng của bạn được biểu thị bằng biểu tượng và nhãn trong Trang chia sẻ nội dung trong Android và trình phân giải ý định. Cả hai đều được xác định trong tệp kê khai. Bạn có thể đặt nhãn bộ lọc ý định hoặc hoạt động để cung cấp thêm bối cảnh.

Kể từ Android 10 (cấp độ API 29), Trang chia sẻ nội dung trong Android chỉ sử dụng các biểu tượng được đặt trong tệp kê khai trên thẻ application. Android bỏ qua các biểu tượng được đặt trên thẻ intent-filter và activity.

Nhận nội dung đa dạng thức

Mặc dù ý định ACTION_SEND cho phép nhận dữ liệu từ Trang chia sẻ nội dung trong Android và trình phân giải ý định ở cấp độ hoạt động hoặc điều hướng, nhưng các ứng dụng cũng có thể nhận nội dung đa dạng thức (chẳng hạn như hình ảnh, video, tệp âm thanh và văn bản được tạo kiểu) thông qua các hoạt động tương tác trực tiếp trên giao diện người dùng. Các cơ chế này bao gồm:

  • Dán từ bảng nhớ tạm (nhấn và giữ trình đơn)
  • Chèn nội dung đa phương tiện trực tiếp từ bàn phím phần mềm (IME), chẳng hạn như hình dán hoặc ảnh GIF
  • Kéo và thả nội dung từ một ứng dụng khác ở chế độ nhiều cửa sổ hoặc chia đôi màn hình

Trong giao diện người dùng dựa trên Khung hiển thị, Android 12 (cấp độ API 31) và AndroidX Core 1.7 giới thiệu API hợp nhất OnReceiveContentListener. Trình nghe này hợp nhất việc xử lý nội dung từ bảng nhớ tạm, bàn phím và thao tác kéo và thả vào một lệnh gọi lại duy nhất. Để biết hướng dẫn chi tiết về cách triển khai tính năng này trong Khung hiển thị, hãy xem bài viết Nhận nội dung đa dạng thức.

Trong Jetpack Compose, bạn có thể xử lý việc nhận nội dung đa dạng thức được chèn vào các thành phần giao diện người dùng (chẳng hạn như trường văn bản) bằng cách sử dụng đối tượng sửa đổi Modifier.contentReceiver hoặc đối tượng sửa đổi kéo và thả.