Chuyển người dùng đến ứng dụng khác

Một trong những tính năng quan trọng nhất của Android là một ứng dụng có khả năng chuyển người dùng đến ứng dụng khác dựa trên "thao tác" mà ứng dụng đó muốn thực hiện. Ví dụ: nếu ứng dụng của bạn có địa chỉ của một doanh nghiệp mà bạn muốn hiển thị trên bản đồ, thì bạn không phải tạo một hoạt động trong ứng dụng đó để hiển thị bản đồ. Thay vào đó, bạn có thể tạo một yêu cầu xem địa chỉ thông qua Intent. Sau đó, hệ thống Android sẽ khởi động một ứng dụng có thể hiển thị địa chỉ trên bản đồ.

Như đã giải thích trong lớp học đầu tiên, Xây dựng ứng dụng đầu tiên, bạn phải dùng ý định để chuyển đổi giữa các hoạt động trong ứng dụng của mình. Thông thường, bạn thực hiện việc này bằng một ý định tường minh, trong đó xác định chính xác tên lớp của thành phần mà bạn muốn bắt đầu. Tuy nhiên, khi muốn yêu cầu một ứng dụng riêng biệt thực hiện thao tác, chẳng hạn như "xem bản đồ", bạn sẽ phải dùng ý định ngầm ẩn.

Bài học này sẽ hướng dẫn bạn cách tạo ý định ngầm ẩn cho một thao tác cụ thể, cũng như cách dùng ý định đó để bắt đầu một hoạt động thực hiện thao tác trong ứng dụng khác. Ngoài ra, bạn cũng có thể xem video được nhúng ở đây để hiểu lý do cần phải thêm hoạt động kiểm tra thời gian chạy cho ý định ngầm ẩn của mình.

Xây dựng một ý định ngầm ẩn

Ý định ngầm ẩn không khai báo tên lớp của thành phần sẽ bắt đầu mà khai báo thao tác sẽ thực hiện. Thao tác chỉ định việc bạn muốn làm, chẳng hạn như xem, chỉnh sửa, gửi hoặc tải nội dung nào đó.

Liên kết các thao tác theo ý định với dữ liệu

Ý định cũng thường bao gồm dữ liệu liên kết với thao tác, chẳng hạn như địa chỉ bạn muốn xem hoặc thư email bạn muốn gửi. Tuỳ thuộc vào ý định mà bạn muốn tạo, dữ liệu có thể là Uri, một trong số các loại dữ liệu khác hoặc ý định có thể không cần dữ liệu.

Nếu dữ liệu là Uri thì bạn có thể dùng một hàm khởi tạo Intent() đơn giản để xác định thao tác và dữ liệu.

Ví dụ: dưới đây là cách tạo ý định bắt đầu cuộc gọi điện thoại bằng việc sử dụng dữ liệu Uri để chỉ định số điện thoại:

Kotlin

val callIntent: Intent = Uri.parse("tel:5551234").let { number ->
    Intent(Intent.ACTION_DIAL, number)
}

Java

Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);

Khi ứng dụng của bạn gọi ý định này bằng cách gọi startActivity(), ứng dụng Điện thoại sẽ bắt đầu cuộc gọi đến một số điện thoại cụ thể.

Dưới đây là một vài ý định khác cùng với cặp thao tác và dữ liệu Uri tương ứng:

Xem một bản đồ

Kotlin

// Map point based on address
val mapIntent: Intent = Uri.parse(
        "geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"
).let { location ->
    // Or map point based on latitude/longitude
    // val location: Uri = Uri.parse("geo:37.422219,-122.08364?z=14") // z param is zoom level
    Intent(Intent.ACTION_VIEW, location)
}

Java

// Map point based on address
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// Or map point based on latitude/longitude
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

Xem một trang web

Kotlin

val webIntent: Intent = Uri.parse("https://www.android.com").let { webpage ->
    Intent(Intent.ACTION_VIEW, webpage)
}

Java

Uri webpage = Uri.parse("https://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

Thêm dữ liệu bổ sung vào một ý định

Những loại ý định ngầm ẩn khác yêu cầu dữ liệu "bổ sung" cung cấp loại dữ liệu khác, chẳng hạn như một chuỗi. Bạn có thể thêm một hoặc nhiều phần dữ liệu bổ sung bằng các phương thức putExtra() khác nhau.

Theo mặc định, hệ thống sẽ xác định loại MIME thích hợp mà một ý định yêu cầu dựa trên dữ liệu Uri đi kèm. Nếu không bao gồm Uri trong ý định thì thông thường, bạn nên dùng setType() để chỉ định loại dữ liệu liên kết với ý định. Việc đặt loại MIME sẽ chỉ định thêm những loại hoạt động nào sẽ nhận ý định.

Dưới đây là một số ý định khác có thêm dữ liệu bổ sung để chỉ định thao tác mong muốn:

Gửi email có tệp đính kèm

Kotlin

Intent(Intent.ACTION_SEND).apply {
    // The intent does not have a URI, so declare the "text/plain" MIME type
    type = "text/plain"
    putExtra(Intent.EXTRA_EMAIL, arrayOf("jan@example.com")) // recipients
    putExtra(Intent.EXTRA_SUBJECT, "Email subject")
    putExtra(Intent.EXTRA_TEXT, "Email message text")
    putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"))
    // You can also attach multiple items by passing an ArrayList of Uris
}

Java

Intent emailIntent = new Intent(Intent.ACTION_SEND);
// The intent does not have a URI, so declare the "text/plain" MIME type
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jan@example.com"}); // recipients
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
// You can also attach multiple items by passing an ArrayList of Uris

Tạo sự kiện trên lịch

Lưu ý: Chỉ API cấp 14 trở lên mới hỗ trợ ý định này cho sự kiện trên lịch.

Kotlin

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent(Intent.ACTION_INSERT, Events.CONTENT_URI).apply {
    val beginTime: Calendar = Calendar.getInstance().apply {
        set(2021, 0, 23, 7, 30)
    }
    val endTime = Calendar.getInstance().apply {
        set(2021, 0, 23, 10, 30)
    }
    putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.timeInMillis)
    putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.timeInMillis)
    putExtra(Events.TITLE, "Ninja class")
    putExtra(Events.EVENT_LOCATION, "Secret dojo")
}

Java

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance();
beginTime.set(2021, 0, 23, 7, 30);
Calendar endTime = Calendar.getInstance();
endTime.set(2021, 0, 23, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");

Lưu ý: Bạn cần phải xác định Intent cụ thể nhất có thể. Ví dụ: nếu muốn hiển thị một hình ảnh bằng ý định ACTION_VIEW, bạn nên chỉ định loại MIME là image/*. Việc này sẽ tránh trường hợp ý định kích hoạt các ứng dụng có thể "xem" loại dữ liệu khác (như ứng dụng bản đồ).

Bắt đầu một hoạt động bằng ý định

Sau khi bạn tạo Intent và đặt thông tin bổ sung, hãy gọi startActivity() để gửi thông tin đó đến hệ thống:

Kotlin

startActivity(intent)

Java

startActivity(intent);

Xử lý tình huống trong đó không ứng dụng nào có thể nhận ý định

Mặc dù nhiều ý định được xử lý thành công bởi một ứng dụng khác đã cài đặt trên thiết bị (chẳng hạn như ứng dụng điện thoại, email hoặc lịch), nhưng ứng dụng của bạn nên chuẩn bị cho tình huống trong đó không hoạt động nào có thể xử lý ý định của ứng dụng. Mỗi khi bạn gọi một ý định, hãy sẵn sàng nắm bắt ActivityNotFoundException. Ngoại lệ này sẽ xảy ra nếu không hoạt động nào khác có thể xử lý ý định của ứng dụng:

Kotlin

try {
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

try {
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

Sau khi bạn nắm bắt ngoại lệ này, hãy quyết định những việc ứng dụng nên làm tiếp theo. Bước tiếp theo này phụ thuộc vào các đặc điểm cụ thể của ý định mà bạn cố gọi. Ví dụ: nếu bạn biết một ứng dụng cụ thể có thể xử lý ý định, hãy cung cấp đường liên kết để người dùng tải ứng dụng đó xuống. Bạn có thể tìm hiểu thêm về cách liên kết đến sản phẩm của bạn trên Google Play.

Hộp thoại phân định

Nếu xác định được nhiều hoạt động có thể xử lý ý định, thì hệ thống sẽ hiển thị một hộp thoại (đôi khi gọi là "hộp thoại phân định") để người dùng chọn ứng dụng sẽ sử dụng, như minh hoạ trong hình 1. Nếu chỉ có một hoạt động xử lý ý định, thì hệ thống sẽ bắt đầu ngay hoạt động đó.

Một bảng điều khiển xuất hiện ở gần cuối màn hình. Bảng điều khiển này liệt kê các ứng dụng có thể xử lý ý định.

Hình 1. Ví dụ về hộp thoại lựa chọn xuất hiện khi nhiều ứng dụng có thể xử lý một ý định.

Ví dụ đầy đủ

Dưới đây là một ví dụ đầy đủ cho thấy cách tạo ý định xem bản đồ, xác minh rằng hiện có một ứng dụng để xử lý ý định, sau đó khởi động ứng dụng đó:

Kotlin

// Build the intent.
val location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California")
val mapIntent = Intent(Intent.ACTION_VIEW, location)

// Try to invoke the intent.
try {
    startActivity(mapIntent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

// Build the intent.
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

// Try to invoke the intent.
try {
    startActivity(mapIntent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

Hiển thị trình chọn ứng dụng

Hình 2. Hộp thoại trình chọn.

Xin lưu ý rằng khi bạn bắt đầu một hoạt động bằng cách chuyển Intent cho startActivity() và có nhiều ứng dụng phản hồi ý định đó, người dùng có thể chọn ứng dụng sẽ sử dụng theo mặc định (bằng cách chọn hộp đánh dấu) ở cuối hộp thoại; xem hình 1). Việc này rất hữu ích khi thực hiện một thao tác mà mỗi lần người dùng thường muốn sử dụng cùng một ứng dụng, chẳng hạn như khi mở trang web (người dùng có khả năng sẽ chỉ sử dụng một trình duyệt web) hoặc chụp ảnh (người dùng có khả năng sẽ ưu tiên một máy ảnh).

Tuy nhiên, nếu thao tác cần thực hiện có thể được nhiều ứng dụng xử lý và mỗi lần người dùng có thể ưu tiên một ứng dụng khác – chẳng hạn như với thao tác "chia sẻ", người dùng có thể chia sẻ một mục thông qua nhiều ứng dụng – bạn nên hiển thị rõ ràng hộp thoại trình chọn như minh hoạ trong hình 2. Hộp thoại trình chọn buộc người dùng mỗi lần đều phải chọn ứng dụng sẽ sử dụng cho thao tác (người dùng không thể chọn ứng dụng mặc định cho thao tác đó).

Để hiển thị trình chọn, hãy tạo Intent bằng createChooser() và chuyển ý định đó vào startActivity(). Ví dụ:

Kotlin

val intent = Intent(Intent.ACTION_SEND)

// Create intent to show chooser
val chooser = Intent.createChooser(intent, /* title */ null)

// Try to invoke the intent.
try {
    startActivity(chooser)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

Intent intent = new Intent(Intent.ACTION_SEND);

// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, /* title */ null);

// Try to invoke the intent.
try {
    startActivity(chooser);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

Đoạn mã này hiển thị một hộp thoại chứa danh sách các ứng dụng phản hồi ý định được chuyển vào phương thức createChooser(). Tham số title có thể được cung cấp nếu thao tác không phải là ACTION_SEND hoặc ACTION_SEND_MULTIPLE