lightbulb_outline Help shape the future of the Google Play Console, Android Studio, and Firebase. Start survey

Ý định và Bộ lọc Ý định

Intent là một đối tượng nhắn tin mà bạn có thể sử dụng để yêu cầu một hành động từ một thành phần ứng dụng khác. Mặc dù các ý định sẽ tạo điều kiện cho giao tiếp giữa các thành phần bằng một vài cách, có ba trường hợp sử dụng cơ bản:

  • Để bắt đầu một hoạt động:

    Activity biểu diễn một màn hình đơn trong một ứng dụng. Bạn có thể bắt đầu một thực thể mới của một Activity bằng cách chuyển Intent sang startActivity(). Intent mô tả hoạt động cần bắt đầu và mang theo mọi dữ liệu cần thiết.

    Nếu bạn muốn nhận một kết quả từ hoạt động khi nó hoàn thành, hãy gọi startActivityForResult(). Hoạt động của bạn nhận được kết quả dưới dạng một đối tượng Intent riêng biệt trong lệnh gọi lại onActivityResult() của hoạt động của bạn. Để biết thêm thông tin, hãy xem hướng dẫn Hoạt động.

  • Để bắt đầu một dịch vụ:

    Service là một thành phần có chức năng thực hiện các thao tác dưới nền mà không cần giao diện người dùng. Bạn có thể bắt đầu một dịch vụ để thực hiện một thao tác một lần (chẳng hạn như tải xuống một tệp) bằng cách chuyển Intent tới startService(). Intent mô tả dịch vụ cần bắt đầu và mang theo mọi dữ liệu cần thiết.

    Nếu dịch vụ được thiết kế với một giao diện máy khách-máy chủ, bạn có thể gắn kết với dịch vụ từ một thành phần khác bằng cách chuyển Intent sang bindService(). Để biết thêm thông tin, hãy xem hướng dẫn Dịch vụ.

  • Để chuyển một quảng bá:

    Quảng bá là một tin nhắn mà bất kỳ ứng dụng nào cũng có thể nhận được. Hệ thống sẽ chuyển các quảng bá khác nhau tới các sự kiện hệ thống, chẳng hạn như khi hệ thống khởi động hoặc thiết bị bắt đầu sạc. Bạn có thể chuyển một quảng bá tới các ứng dụng khác bằng cách chuyển một Intent tới sendBroadcast(), sendOrderedBroadcast(), hoặc sendStickyBroadcast().

Các Loại Ý định

Có hai loại ý định:

  • Ý định biểu thị quy định thành phần cần bắt đầu theo tên (tên lớp hoàn toàn đạt tiêu chuẩn ). Thường bạn sẽ sử dụng một ý định biểu thị để bắt đầu một thành phần trong ứng dụng của chính mình, vì bạn biết tên lớp của hoạt động hay dịch vụ mà mình muốn bắt đầu. Ví dụ , bắt đầu một hoạt động mới để hồi đáp một hành động của người dùng hay bắt đầu một dịch vụ để tải xuống tệp dưới nền.
  • Ý định không biểu thị không chỉ định một thành phần cụ thể mà thay vào đó, sẽ khai báo một hành động thông thường cần thực hiện, cho phép một thành phần từ một ứng dụng khác xử lý nó. Ví dụ, nếu bạn muốn hiển thị cho người dùng một vị trí trên bản đồ, bạn có thể sử dụng một ý định không biểu thị để yêu cầu một ứng dụng có khả năng khác hiển thị một vị trí được chỉ định trên bản đồ.

Khi bạn tạo một ý định biểu thị để bắt đầu một hoạt động hoặc dịch vụ, hệ thống ngay lập tức sẽ bắt đầu thành phần ứng dụng được quy định trong đối tượng Intent.

Hình 1. Minh họa về cách một ý định không biểu thị được chuyển thông qua hệ thống để bắt đầu một hoạt động khác: [1] Hoạt động A tạo một Intent bằng một mô tả hành động và chuyển nó cho startActivity(). [2] Hệ thống Android tìm kiếm tất cả ứng dụng xem có một bộ lọc ý định khớp với ý định đó không. Khi tìm thấy kết quả khớp, [3] hệ thống sẽ bắt đầu hoạt động so khớp đó (Hoạt động B) bằng cách gọi ra phương pháp onCreate() và chuyển nó cho Intent.

Khi bạn tạo một ý định không biểu thị, hệ thống Android sẽ tìm kiếm thành phần phù hợp để bắt đầu bằng cách so sánh nội dung của ý định với các bộ lọc ý định được khai báo trong tệp bản kê khai của các ứng dụng khác trên thiết bị. Nếu ý định khớp với một bộ lọc ý định, hệ thống sẽ bắt đầu thành phần đó và chuyển cho nó đối tượng Intent. Nếu có nhiều bộ lọc ý định tương thích, hệ thống sẽ hiển thị một hộp thoại để người dùng có thể chọn ứng dụng sẽ sử dụng.

Bộ lọc ý định là một biểu thức trong tệp bản kê khai của một ứng dụng, có chức năng chỉ định loại ý định mà thành phần muốn nhận. Ví dụ, bằng cách khai báo một bộ lọc ý định cho một hoạt động, bạn giúp các ứng dụng khác có thể trực tiếp bắt đầu hoạt động của mình với một loại ý định nhất định. Tương tự, nếu bạn không khai báo bất kỳ bộ lọc ý định nào cho một hoạt động, khi đó nó chỉ có thể được bắt đầu bằng một ý định biểu thị.

Chú ý: Để đảm bảo ứng dụng của bạn được bảo mật, luôn sử dụng một ý định biểu thị khi bắt đầu một Service và không được khai báo bộ lọc ý định cho các dịch vụ của bạn. Việc sử dụng một ý định không biểu thị để bắt đầu một dịch vụ sẽ là một nguy cơ về bảo mật vì bạn không thể chắc chắn dịch vụ nào sẽ hồi đáp ý định đó, và người dùng không thể thấy dịch vụ nào bắt đầu. Bắt đầu với Android 5.0 (API mức 21), hệ thống sẽ đưa ra lỗi ngoại lệ nếu bạn gọi bindService() bằng một ý định không biểu thị.

Xây dựng một Ý định

Đối tượng Intent mang thông tin mà hệ thống Android sử dụng để xác định thành phần nào sẽ bắt đầu (chẳng hạn như tên thành phần chính xác hoặc thể loại thành phần mà sẽ nhận ý định), cộng với thông tin mà thành phần nhận sử dụng để thực hiện hành động cho phù hợp (chẳng hạn như hành động sẽ thực hiện và dữ liệu để dựa vào đó mà thực hiện).

Thông tin chính chứa trong một Intent như sau:

Tên thành phần
Tên của thành phần sẽ bắt đầu.

Nội dung này không bắt buộc, nhưng đó là một thông tin trọng yếu để khiến một ý định trở nên biểu thị, có nghĩa là ý định nên chỉ được chuyển tới thành phần ứng dụng được xác định bởi tên thành phần đó. Nếu thiếu một tên thành phần, ý định trở thành không biểu thị và hệ thống sẽ quyết định thành phần nào nhận ý định đó dựa trên các thông tin còn lại của ý định (chẳng hạn như hành động, dữ liệu và thể loại—được mô tả bên dưới). Vì vậy, nếu bạn bắt đầu một thành phần cụ thể trong ứng dụng của mình, bạn nên chỉ định tên thành phần.

Lưu ý: Khi bắt đầu một Service, bạn nên luôn chỉ định tên thành phần. Nếu không, bạn không thể chắc chắn dịch vụ nào sẽ hồi đáp ý định và người dùng không thể thấy dịch vụ nào bắt đầu.

Trường này của Intent là một đối tượng ComponentName mà bạn có thể chỉ định bằng cách sử dụng một tên lớp hoàn toàn đủ tiêu chuẩn của thành phần đích, bao gồm tên gói của ứng dụng. Ví dụ, com.example.ExampleActivity. Bạn có thể đặt tên thành phần bằng setComponent(), setClass(), setClassName(), hoặc bằng hàm dựng Intent.

Hành động
Một xâu quy định hành động thông thường sẽ thực hiện (chẳng hạn như xem hoặc chọn).

Trong trường hợp một ý định quảng bá, đây là hành động đã diễn ra và đang được báo cáo. Hành động này quyết định phần lớn cách thức xác định cấu trúc phần còn lại của ý định—đặc biệt là những gì chứa trong dữ liệu và phụ thêm.

Bạn có thể quy định các hành động của chính mình để các ý định bên trong ứng dụng của bạn sử dụng (hoặc để các ứng dụng khác sử dụng nhằm gọi ra các thành phần trong ứng dụng của mình), nhưng bạn nên thường xuyên sử dụng hằng số hành động được định nghĩa bởi lớp Intent hoặc các lớp khuôn khổ khác. Sau đây là một số hành động thường dùng để bắt đầu một hoạt động:

ACTION_VIEW
Sử dụng hành động này trong một ý định với startActivity() khi bạn có một số thông tin mà một hoạt động có thể hiển thị cho người dùng, chẳng hạn như ảnh để xem trong một ứng dụng bộ sưu tập ảnh, hay địa chỉ để xem trong ứng dụng bản đồ.
ACTION_SEND
Còn được biết đến như là ý định "chia sẻ", bạn nên sử dụng kiểu này trong một ý định với startActivity() khi bạn có một số dữ liệu mà người dùng có thể chia sẻ thông qua một ứng dụng khác, chẳng hạn như một ứng dụng e-mail hay ứng dụng chia sẻ mạng xã hội.

Xem tham chiếu lớp Intent để biết thêm hằng số có chức năng định nghĩa các hành động thông thường. Những hành động khác được định nghĩa ở phần khác trong khuôn khổ Android, chẳng hạn như trong Settings đối với những hành động có chức năng mở màn hình cụ thể trong ứng dụng Cài đặt của hệ thống.

Bạn có thể quy định hành động cho một ý định với setAction() hoặc với một hàm dựng Intent.

Nếu bạn định nghĩa các hành động của chính mình, nhớ nêu tên gói ứng dụng của bạn làm tiền tố. Ví dụ:

static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
Dữ liệu
URI (một đối tượng Uri) tham chiếu dữ liệu sẽ được hành động dựa trên nó và/hoặc kiểu MIME của dữ liệu đó. Kiểu dữ liệu được cung cấp thường sẽ bị chi phối bởi hành động của ý định. Ví dụ, nếu hành động là ACTION_EDIT, dữ liệu cần chứa URI của tài liệu cần chỉnh sửa.

Khi tạo một ý định, một điều thường quan trọng đó là quy định kiểu dữ liệu (kiểu MIME của nó) ngoài URI của nó. Ví dụ, một hoạt động có thể hiển thị hình ảnh có thể sẽ không phát được tệp âm thanh, ngay cả khi định dạng URI có thể tương tự. Vì thế, việc quy định kiểu MIME cho dữ liệu của bạn sẽ giúp hệ thống Android tìm được thành phần tốt nhất để nhận ý định của bạn. Tuy nhiên, kiểu MIME đôi khi có thể được suy ra từ URI—cụ thể, khi dữ liệu là một URI content:, có chức năng cho biết dữ liệu nằm trên thiết bị và được kiểm soát bởi một ContentProvider, điều này khiến kiểu MIME của dữ liệu hiển thị đối với hệ thống.

Để chỉ đặt URI dữ liệu, hãy gọi setData(). Để chỉ đặt kiểu MIME, hãy gọi setType(). Nếu cần, bạn bạn có thể công khai đặt cả hai với setDataAndType().

Chú ý: Nếu bạn muốn đặt cả URI và kiểu MIME, không gọi setData()setType() vì chúng sẽ vô hiệu hóa giá trị của nhau. Luôn sử dụng setDataAndType() để đặt cả URI và kiểu MIME.

Thể loại
Một xâu chứa thông tin bổ sung về kiểu thành phần sẽ xử lý ý định. Trong một ý định có thể chứa nhiều mô tả thể loại, nhưng hầu hết các ý định lại không yêu cầu thể loại. Sau đây là một số thể loại thường gặp:
CATEGORY_BROWSABLE
Hoạt động mục tiêu cho phép chính nó được bắt đầu bởi một trình duyệt web để hiển thị dữ liệu được một liên kết tham chiếu—chẳng hạn như một hình ảnh hay thư e-mail.
CATEGORY_LAUNCHER
Hoạt động là hoạt động ban đầu của một tác vụ và được liệt kê trong trình khởi chạy ứng dụng của hệ thống.

Xem mô tả lớp Intent để biết danh sách đầy đủ về các thể loại.

Bạn có thể quy định một thể loại bằng addCategory().

Những tính chất này được liệt kê ở trên (tên thành phần, hành động, dữ liệu và thể loại) biểu hiện các đặc điểm xác định của một ý định. Bằng cách đọc những tính chất này, hệ thống Android có thể quyết định nó sẽ bắt đầu thành phần ứng dụng nào.

Tuy nhiên, một ý định có thể mang thông tin bổ sung không ảnh hưởng tới cách nó được giải quyết đối với một thành phần ứng dụng. Một ý định cũng có thể cung cấp:

Phụ thêm
Các cặp khóa-giá trị mang thông tin bổ sung cần thiết để hoàn thành hành động được yêu cầu. Giống như việc một số hành động sử dụng các kiểu URI dữ liệu riêng, một số hành động cũng sử dụng các phần phụ thêm riêng.

Bạn có thể thêm dữ liệu phụ thêm bằng các phương pháp putExtra() khác nhau, mỗi phương pháp chấp nhận hai tham số: tên khóa và giá trị. Bạn cũng có thể tạo một đối tượng Bundle bằng tất cả dữ liệu phụ thêm, sau đó chèn Bundle vào Intent bằng putExtras().

Ví dụ, khi tạo một ý định để gửi một e-mail bằng ACTION_SEND, bạn có thể chỉ định người nhận "tới" bằng khóa EXTRA_EMAIL, và chỉ định "chủ đề" bằng khóa EXTRA_SUBJECT.

Lớp Intent quy định nhiều hằng số EXTRA_* cho các kiểu dữ liệu chuẩn hóa. Nếu bạn cần khai báo các khóa phụ thêm của riêng mình (cho những ý định mà ứng dụng của bạn nhận), hãy chắc chắn nêu tên gói ứng dụng của bạn làm tiền tố. Ví dụ:

static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
Cờ
Cờ được định nghĩa trong lớp Intent có chức năng như siêu dữ liệu cho ý định. Cờ có thể chỉ lệnh hệ thống Android về cách khởi chạy một hoạt động (ví dụ, hoạt động sẽ thuộc về tác vụ nào ) và cách xử lý sau khi nó được khởi chạy (ví dụ, nó có thuộc về danh sách hoạt động gần đây hay không).

Để biết thêm thông tin, hãy xem phương pháp setFlags().

Ví dụ về ý định biểu thị

Ý định biểu thị là ý định mà bạn sử dụng để khởi chạy một thành phần ứng dụng cụ thể chẳng hạn như một hoạt động hay dịch vụ cụ thể trong ứng dụng của bạn. Để tạo một ý định biểu thị, hãy định nghĩa tên thành phần cho đối tượng Intent —tất cả các tính chất ý định khác đều không bắt buộc.

Ví dụ, nếu bạn đã xây dựng một dịch vụ trong ứng dụng của mình, đặt tên là DownloadService, được thiết kế để tải xuống một tệp từ web, bạn có thể bắt đầu nó bằng mã sau:

// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

Hàm dựng Intent(Context, Class) cung cấp cho ứng dụng Context và thành phần một đối tượng Class. Như vậy, ý định này rõ ràng sẽ bắt đầu lớp DownloadService trong ứng dụng.

Để biết thêm thông tin về việc xây dựng và bắt đầu một dịch vụ, hãy xem hướng dẫn Dịch vụ.

Ví dụ về ý định không biểu thị

Ý định không biểu thị quy định một hành động mà có thể gọi ra bất kỳ ứng dụng nào trên thiết bị mà có khả năng thực hiện hành động đó. Việc sử dụng ý định không biểu thị có ích khi ứng dụng của bạn không thể thực hiện hành động, nhưng các ứng dụng khác có thể và bạn muốn người dùng chọn ứng dụng sẽ sử dụng.

Ví dụ, nếu bạn có nội dung mà mình muốn người dùng chia sẻ với người khác, hãy tạo một ý định với hành động ACTION_SEND và bổ sung phần phụ thêm quy định nội dung sẽ chia sẻ. Khi bạn gọi startActivity() bằng ý định đó, người dùng có thể chọn một ứng dụng để chia sẻ nội dung thông qua đó.

Chú ý: Có thể là người dùng sẽ không có bất kỳ ứng dụng nào xử lý được ý định không biểu thị mà bạn gửi tới startActivity(). Nếu chuyện đó xảy ra, phương pháp gọi sẽ thất bại và ứng dụng của bạn sẽ gặp lỗi. Để xác minh rằng một hoạt động sẽ nhận được ý định, hãy gọi resolveActivity() trên đối tượng Intent của bạn. Nếu kết quả không rỗng thì có ít nhất một ứng dụng có thể xử lý ý định và sẽ an toàn nếu gọi startActivity(). Nếu kết quả rỗng, bạn không nên sử dụng ý định và, nếu có thể, bạn nên vô hiệu hóa tính năng phát hành ý định.

// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

Lưu ý: Trong trường hợp này, URI không được sử dụng, nhưng kiểu dữ liệu của ý định sẽ được khai báo để quy định nội dung được thực hiện bởi phần phụ thêm.

Khi startActivity() được gọi, hệ thống sẽ kiểm tra tất cả ứng dụng đã cài đặt để xác định những ứng dụng có thể xử lý kiểu ý định này (một ý định với hành động ACTION_SEND và có mang dữ liệu "văn bản/thuần"). Nếu chỉ có một ứng dụng có thể xử lý nó, ứng dụng đó sẽ mở ngay lập tức và được cấp cho ý định. Nếu có nhiều hoạt động chấp nhận ý định, hệ thống sẽ hiển thị một hộp thoại để người dùng có thể chọn ứng dụng sẽ sử dụng.

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

Bắt buộc một bộ chọn ứng dụng

Khi có nhiều hơn một ứng dụng hồi đáp ý định không biểu thị của bạn, người dùng có thể chọn ứng dụng nào sẽ sử dụng và đặt ứng dụng đó làm lựa chọn mặc định cho hành động. Điều này tốt khi thực hiện một hành động mà người dùng có thể muốn sử dụng ứng dụng tương tự từ lúc này trở đi, chẳng hạn như khi mở một trang web (người dùng thường thích ưu tiên sử dụng chỉ một trình duyệt web).

Tuy nhiên, nếu nhiều ứng dụng có thể hồi đáp ý định và người dùng có thể muốn sử dụng mỗi lần một ứng dụng khác, bạn nên công khai hiển thị một hộp thoại bộ chọn. Hộp thoại bộ chọn yêu cầu người dùng phải chọn ứng dụng sẽ sử dụng mỗi lần cho hành động (người dùng không thể chọn một ứng dụng mặc định cho hành động). Ví dụ, khi ứng dụng của bạn thực hiện "chia sẻ" với hành động ACTION_SEND, người dùng có thể muốn chia sẻ bằng cách sử dụng một ứng dụng khác tùy vào tình hình thực tế của họ, vì thế bạn nên luôn sử dụng hộp thoại bộ chọn như minh họa trong hình 2.

Để hiển thị bộ chọn, hãy tạo một Intent bằng cách sử dụng createChooser() và chuyển nó sang startActivity(). Ví dụ:

Intent sendIntent = new Intent(Intent.ACTION_SEND);
...

// Always use string resources for UI text.
// This says something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// Create intent to show the chooser dialog
Intent chooser = Intent.createChooser(sendIntent, title);

// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

Một hộp thoại hiển thị với một danh sách ứng dụng hồi đáp lại ý định được chuyển sang phương pháp createChooser() và sử dụng văn bản được cung cấp làm tiêu đề của hộp thoại.

Nhận một Ý định Không biểu thị

Để quảng cáo những ý định không biểu thị mà ứng dụng của bạn có thể nhận, hãy khai báo một hoặc nhiều bộ lọc ý định cho từng thành phần ứng dụng của bạn với một phần tử <intent-filter> trong tệp bản kê khai của mình. Mỗi bộ lọc ý định sẽ quy định loại ý định mà nó chấp nhận dựa trên hành động, dữ liệu và thể loại của ý định. Hệ thống sẽ chỉ chuyển một ý định không biểu thị tới thành phần ứng dụng của bạn nếu ý định đó có thể chuyển qua một trong các bộ lọc ý định của bạn.

Lưu ý: Ý định biểu thị luôn được chuyển tới mục tiêu của mình, không phụ thuộc vào bất kỳ bộ lọc ý định nào mà thành phần khai báo.

Một thành phần ứng dụng nên khai báo các bộ lọc riêng cho từng công việc duy nhất mà nó có thể thực hiện. Ví dụ, một hoạt động trong một ứng dụng bộ sưu tập ảnh có thể có hai bộ lọc: một bộ lọc để xem một hình ảnh và một bộ lọc để chỉnh sửa một hình ảnh. Khi hoạt động bắt đầu, nó sẽ kiểm tra Intent và quyết định cách xử lý dựa trên thông tin trong Intent (chẳng hạn như có hiển thị các điều khiển của trình chỉnh sửa hoặc không).

Mỗi bộ lọc ý định sẽ được định nghĩa bởi một phần tử <intent-filter> trong tệp bản kê khai của ứng dụng, được lồng trong thành phần ứng dụng tương ứng (chẳng hạn như một phần tử <activity> ). Bên trong <intent-filter>, bạn có thể quy định loại ý định sẽ chấp nhận bằng cách sử dụng một hoặc nhiều phần tử trong ba phần tử sau:

<action>
Khai báo hành động ý định được chấp nhận, trong thuộc tính name. Giá trị phải là giá trị xâu ký tự của một hành động chứ không phải hằng số lớp.
<data>
Khai báo kiểu dữ liệu được chấp nhận, bằng cách sử dụng một hoặc nhiều thuộc tính quy định các khía cạnh của URI dữ liệu (scheme, host, port, path, v.v.) và kiểu MIME.
<category>
Khai báo thể loại ý định được chấp nhận, trong thuộc tính name. Giá trị phải là giá trị xâu ký tự của một hành động chứ không phải hằng số lớp.

Lưu ý: Để nhận các ý định không biểu thị, bạn phải nêu thể loại CATEGORY_DEFAULT trong bộ lọc ý định. Các phương pháp startActivity()startActivityForResult() xử lý tất cả ý định như thể chúng khai báo thể loại CATEGORY_DEFAULT. Nếu bạn không khai báo thể loại này trong bộ lọc ý định của mình, không có ý định không biểu thị nào sẽ phân giải thành hoạt động của bạn.

Ví dụ, sau đây là một khai báo hoạt động với một bộ lọc ý định để nhận một ý định ACTION_SEND khi kiểu dữ liệu là văn bản:

<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

Không sao nếu tạo một bộ lọc chứa nhiều hơn một thực thể của &lt;action&gt;, &lt;data&gt;, hoặc &lt;category&gt;. Nếu làm vậy, bạn chỉ cần chắc chắn rằng thành phần có thể xử lý bất kỳ và tất cả các cách kết hợp những phần tử bộ lọc đó.

Khi bạn muốn xử lý nhiều kiểu ý định, nhưng chỉ theo các cách kết hợp cụ thể giữa hành động, dữ liệu và kiểu thể loại, khi đó bạn cần tạo nhiều bộ lọc ý định.

Ý định không biểu thị sẽ được kiểm tra dựa trên một bộ lọc bằng cách so sánh ý định với từng phần tử trong số ba phần tử. Để được chuyển tới thành phần, ý định phải vượt qua tất cả ba lần kiểm tra. Nếu không khớp với thậm chí chỉ một lần thì hệ thống Android sẽ không chuyển ý định tới thành phần. Tuy nhiên, vì một thành phần có thể có nhiều bộ lọc ý định, ý định mà không chuyển qua một trong các bộ lọc của thành phần có thể chuyển qua trên một bộ lọc khác. Bạn có thể tìm hiểu thêm thông tin về cách hệ thống giải quyết ý định trong phần bên dưới về Giải quyết Ý định.

Chú ý: Để tránh vô ý chạy Service của một ứng dụng khác, hãy luôn sử dụng một ý định biểu thị để bắt đầu dịch vụ của chính bạn và không được khai báo các bộ lọc ý định cho dịch vụ của bạn.

Lưu ý: Đối với tất cả hoạt động, bạn phải khai báo các bộ lọc ý định của mình trong một tệp bản kê khai. Tuy nhiên, các bộ lọc cho hàm nhận quảng bá có thể được đăng ký linh hoạt bằng cách gọi registerReceiver(). Sau đó, bạn có thể bỏ đăng ký hàm nhận đó bằng unregisterReceiver(). Làm vậy sẽ cho phép ứng dụng của bạn lắng nghe các quảng bá cụ thể chỉ trong một khoảng thời gian xác định trong khi ứng dụng của bạn đang chạy.

Ví dụ về bộ lọc

Để hiểu hơn về một số hành vi của bộ lọc ý định, hãy xem đoạn mã HTML sau từ tệp bản kê khai của một ứng dụng chia sẻ mạng xã hội.

<activity android:name="MainActivity">
    <!-- This activity is the main entry, should appear in app launcher -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name="ShareActivity">
    <!-- This activity handles "SEND" actions with text data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
    <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <action android:name="android.intent.action.SEND_MULTIPLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="application/vnd.google.panorama360+jpg"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="video/*"/>
    </intent-filter>
</activity>

Hoạt động thứ nhất, MainActivity, là điểm mục nhập chính của ứng dụng—hoạt động này sẽ mở khi người dùng khởi tạo ban đầu ứng dụng bằng biểu tượng trình khởi chạy:

  • Hành động ACTION_MAIN thể hiện đây là điểm mục nhập chính và không yêu cầu bất kỳ dữ liệu ý định nào.
  • Thể loại CATEGORY_LAUNCHER cho biết rằng biểu tượng của hoạt động này nên được đặt trong trình khởi chạy ứng dụng của hệ thống. Nếu phần tử &lt;activity&gt; không quy định một biểu tượng bằng icon, khi đó hệ thống sẽ sử dụng biểu tượng từ phần tử &lt;application&gt; .

Hai nội dung này phải được ghép đôi cùng nhau để hoạt động xuất hiện trong trình khởi chạy ứng dụng.

Hoạt động thứ hai, ShareActivity, có mục đích để tạo điều kiện chia sẻ nội dung văn bản và phương tiện. Mặc dù người dùng có thể nhập hoạt động này bằng cách điều hướng tới nó từ MainActivity, họ cũng có thể nhập ShareActivity trực tiếp từ một ứng dụng khác mà phát hành ý định không biểu thị khớp với một trong hai bộ lọc ý định.

Lưu ý: Kiểu MIME, application/vnd.google.panorama360+jpg, là một kiểu dữ liệu đặc biệt quy định ảnh chụp toàn cảnh mà bạn có thể xử lý bằng các API Google panorama.

Sử dụng một Ý định Chờ

Đối tượng PendingIntent là một trình bao bọc xung quanh một đối tượng Intent. Mục đích chính của một PendingIntent là cấp quyền cho một ứng dụng ngoài để sử dụng Intent chứa trong nó như thể nó được thực thi từ tiến trình của chính ứng dụng của bạn.

Các trường hợp sử dụng chính đối với một ý định chờ bao gồm:

  • Khai báo một ý định cần được thực thi khi người dùng thực hiện một hành động bằng Thông báo của bạn (NotificationManager của hệ thống Android thực thi Intent).
  • Khai báo một ý định cần được thực thi khi người dùng thực hiện một hành động bằng App Widget của bạn (ứng dụng màn hình Trang chủ thực thi Intent).
  • Khai báo một ý định cần được thực thi tại một thời điểm xác định trong tương lai ( AlarmManager của hệ thống Android thực thi Intent).

Vì mỗi đối tượng Intent được thiết kế để được xử lý bởi một loại thành phần ứng dụng cụ thể (hoặc là Activity, Service, hay BroadcastReceiver), vì thế PendingIntent cũng phải được tạo lập với cân nhắc tương tự. Khi sử dụng một ý định chờ, ứng dụng của bạn sẽ không thực thi ý định bằng một lệnh gọi chẳng hạn như startActivity(). Thay vào đó, bạn phải khai báo loại thành phần theo ý định khi bạn tạo lập PendingIntent bằng cách gọi phương pháp trình tạo lập tương ứng:

Trừ khi ứng dụng của bạn đang nhận ý định chờ từ các ứng dụng khác, các phương pháp để tạo lập PendingIntent trên là những phương pháp PendingIntent duy nhất mà bạn sẽ cần.

Mỗi phương pháp sẽ lấy ứng dụng Context hiện tại, Intent mà bạn muốn bao bọc, và một hoặc nhiều cờ quy định cách thức sử dụng ý định (chẳng hạn như ý định có thể được sử dụng nhiều hơn một lần hay không).

Bạn có thể tham khảo thêm thông tin về việc sử dụng ý định chờ trong tài liệu cho từng trường hợp sử dụng tương ứng chẳng hạn như trong hướng dẫn về API Thông báoApp Widgets.

Giải quyết Ý định

Khi hệ thống nhận được một ý định không biểu thị nhằm bắt đầu một hoạt động, nó sẽ tìm hoạt động tốt nhất cho ý định đó bằng cách so sánh ý định với các bộ lọc ý định dựa trên ba phương diện:

  • Hành động của ý định
  • Dữ liệu của ý định (cả URI và kiểu dữ liệu)
  • Thể loại của ý định

Các phần sau mô tả cách một ý định được so khớp với (các) thành phần phù hợp về phương diện bộ lọc ý định được khai báo như thế nào trong tệp bản kê khai của một ứng dụng.

Kiểm tra hành động

Để quy định các hành động của ý định được chấp nhận, một bộ lọc ý định có thể khai báo 0 phần tử &lt;action&gt; hoặc nhiều hơn. Ví dụ:

<intent-filter>
    <action android:name="android.intent.action.EDIT" />
    <action android:name="android.intent.action.VIEW" />
    ...
</intent-filter>

Để vượt qua bộ lọc này, hành động được quy định trong Intent phải khớp với một trong các hành động được liệt kê trong bộ lọc.

Nếu bộ lọc không liệt kê bất kỳ hành động nào thì sẽ không có gì để ý định so khớp, vì thế tất cả ý định sẽ không vượt qua kiểm tra. Tuy nhiên, nếu một Intent không quy định một hành động, nó sẽ vượt qua kiểm tra (miễn là bộ lọc chứa ít nhất một hành động).

Kiểm tra thể loại

Để quy định các thể loại của ý định được chấp nhận, một bộ lọc ý định có thể khai báo 0 phần tử &lt;category&gt; hoặc nhiều hơn. Ví dụ:

<intent-filter>
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    ...
</intent-filter>

Để một ý định vượt qua kiểm tra thể loại, mỗi thể loại trong Intent phải khớp với một thể loại trong bộ lọc. Trường hợp ngược lại là không cần thiết—bộ lọc ý định có thể khai báo nhiều thể loại hơn được quy định trong IntentIntent sẽ vẫn vượt qua. Vì thế, ý định không có thể loại luôn vượt qua kiểm tra này, không phụ thuộc vào những thể loại nào được khai báo trong bộ lọc.

Lưu ý: Android sẽ tự động áp dụng thể loại CATEGORY_DEFAULT cho tất cả ý định không biểu thị được chuyển tới startActivity()startActivityForResult(). Vì thế, nếu bạn muốn hoạt động của mình nhận ý định không biểu thị, nó phải nêu một thể loại cho "android.intent.category.DEFAULT" trong các bộ lọc ý định của mình (như được minh họa trong ví dụ &lt;intent-filter&gt; trước đó.

Kiểm tra dữ liệu

Để quy định dữ liệu của ý định được chấp nhận, một bộ lọc ý định có thể khai báo 0 phần tử &lt;data&gt; hoặc nhiều hơn. Ví dụ:

<intent-filter>
    <data android:mimeType="video/mpeg" android:scheme="http" ... />
    <data android:mimeType="audio/mpeg" android:scheme="http" ... />
    ...
</intent-filter>

Mỗi phần tử <data> có thể quy định một cấu trúc URI và kiểu dữ liệu (kiểu phương tiện MIME). Có các thuộc tính riêng — scheme, host, port, và path — cho từng phần của URI:

&lt;scheme&gt;://&lt;host&gt;:&lt;port&gt;/&lt;path&gt;

Ví dụ:

content://com.example.project:200/folder/subfolder/etc

Trong URI này, lược đồ là content, máy chủ là com.example.project, cổng là 200, và đường dẫn là folder/subfolder/etc.

Mỗi thuộc tính sau đều không bắt buộc trong một phần tử &lt;data&gt;, nhưng có sự phụ thuộc mang tính chất tuyến tính:

  • Nếu không quy định một lược đồ thì máy chủ bị bỏ qua.
  • Nếu không quy định một máy chủ thì cổng bị bỏ qua.
  • Nếu không quy định cả lược đồ và máy chủ thì đường dẫn bị bỏ qua.

Khi URI trong một ý định được so sánh với đặc tả URI trong một bộ lọc, nó chỉ được so sánh với các bộ phận của URI được nêu trong bộ lọc. Ví dụ:

  • Nếu một bộ lọc chỉ quy định một lược đồ, tất cả URI có lược đồ đó sẽ khớp với bộ lọc.
  • Nếu một bộ lọc quy định một lược đồ và thẩm quyền nhưng không có đường dẫn, tất cả URI với cùng lược đồ và thẩm quyền sẽ thông qua bộ lọc, không phụ thuộc vào đường dẫn của nó.
  • Nếu bộ lọc quy định một lược đồ, thẩm quyền và đường dẫn, chỉ những URI có cùng lược đồ, thẩm quyền và đường dẫn mới thông qua bộ lọc.

Lưu ý: Đặc tả đường dẫn có thể chứa một ký tự đại diện dấu sao (*) để yêu cầu chỉ khớp một phần với tên đường dẫn.

Kiểm tra dữ liệu so sánh cả URI và kiểu MIME trong ý định với một URI và kiểu MIME được quy định trong bộ lọc. Các quy tắc như sau:

  1. Một ý định mà không chứa URI cũng như kiểu MIME sẽ chỉ vượt qua kiểm tra nếu bộ lọc không quy định bất kỳ URI hay kiểu MIME nào.
  2. Một ý định chứa URI nhưng không có kiểu MIME (không biểu thị cũng như suy luận được từ URI) sẽ chỉ vượt qua kiểm tra nếu URI của nó khớp với định dạng URI của bộ lọc và bộ lọc tương tự không quy định một kiểu MIME.
  3. Một ý định chứa kiểu MIME nhưng không chứa URI sẽ chỉ vượt qua kiểm tra nếu bộ lọc liệt kê cùng kiểu MIME và không quy định một định dạng URI.
  4. Ý định mà chứa cả URI và kiểu MIME (hoặc biểu thị hoặc suy ra được từ URI) sẽ chỉ vượt qua phần kiểu MIME của kiểm tra nếu kiểu đó khớp với kiểu được liệt kê trong bộ lọc. Nó vượt qua phần URI của kiểm tra nếu URI của nó khớp với một URI trong bộ lọc hoặc nếu nó có một content: hoặc file: URI và bộ lọc không quy định một URI. Nói cách khác, một thành phần được giả định là hỗ trợ dữ liệu content:file: nếu bộ lọc của nó liệt kê chỉ một kiểu MIME.

Quy tắc cuối cùng này, quy tắc (d), phản ánh kỳ vọng rằng các thành phần có thể nhận được dữ liệu cục bộ từ một tệp hoặc trình cung cấp nội dung. Vì thế, các bộ lọc của chúng có thể chỉ liệt kê một kiểu dữ liệu và không cần công khai nêu tên content: và các lược đồ file:. Đây là một trường hợp điển hình. Phần tử &lt;data&gt; như sau, ví dụ, sẽ thông báo cho Android biết rằng thành phần có thể nhận được dữ liệu ảnh từ một trình cung cấp nội dung và sẽ hiển thị nó:

<intent-filter>
    <data android:mimeType="image/*" />
    ...
</intent-filter>

Vì hầu hết dữ liệu có sẵn đều được cấp phát bởi các trình cung cấp nội dung, những bộ lọc mà quy định một kiểu dữ liệu chứ không phải URI có lẽ là phổ biến nhất.

Một cấu hình phổ biến khác đó là các bộ lọc có một lược đồ và một kiểu dữ liệu. Ví dụ, một phần tử &lt;data&gt; như sau thông báo cho Android rằng thành phần có thể truy xuất dữ liệu video từ mạng để thực hiện hành động:

<intent-filter>
    <data android:scheme="http" android:type="video/*" />
    ...
</intent-filter>

So khớp ý định

Các ý định được so khớp với các bộ lọc ý định không chỉ để khám phá một thành phần mục tiêu cần kích hoạt, mà còn để khám phá điều gì đó về tập hợp các thành phần trên thiết bị. Ví dụ, ứng dụng Trang chủ đưa trình khởi chạy ứng dụng vào bằng cách tìm tất cả hoạt động có bộ lọc ý định mà quy định hành động ACTION_MAIN và thể loại CATEGORY_LAUNCHER.

Ứng dụng của bạn có thể sử dụng so khớp ý định theo cách tương tự. PackageManager có một tập hợp các phương phápquery...() trả về tất cả thành phần có thể chấp nhận một ý định cụ thể, và một chuỗi các phương pháp resolve...() tương tự để xác định thành phần tốt nhất nhằm hồi đáp lại một ý định. Ví dụ, queryIntentActivities() sẽ trả về một danh sách tất cả hoạt động có thể thực hiện ý định được chuyển qua như một tham đối, và queryIntentServices() trả về một danh sách dịch vụ tương tự. Cả hai phương pháp đều không kích hoạt các thành phần; chúng chỉ liệt kê những thành phần có thể hồi đáp. Có một phương pháp tương tự, queryBroadcastReceivers(), dành cho hàm nhận quảng bá.