page.title=Đại cương về Ứng dụng @jd:body
Ứng dụng Android được viết bằng ngôn ngữ lập trình Java. Bộ công cụ SDK Android sẽ biên dịch mã của bạn—cùng với bất kỳ tệp dữ liệu và tài nguyên nào—vào một APK: một gói Android, đó là một tệp lưu trữ có hậu tố {@code .apk}. Một tệp APK chứa tất cả nội dung của một ứng dụng Android và là tệp mà các thiết bị dựa trên nền tảng Android sử dụng để cài đặt ứng dụng.
Sau khi được cài đặt lên một thiết bị, từng ứng dụng Android sẽ ở bên trong hộp cát bảo mật của chính nó:
Bằng cách này, hệ thống Android triển khai nguyên tắc đặc quyền ít nhất. Cụ thể, theo mặc định, mỗi ứng dụng chỉ có thể truy cập vào các thành phần mà nó cần để thực hiện công việc của mình và không hơn. Điều này tạo ra một môi trường rất bảo mật mà trong đó một ứng dụng không thể truy cập các bộ phận của hệ thống mà nó không được cấp quyền.
Tuy nhiên, có nhiều cách để một ứng dụng chia sẻ dữ liệu với các ứng dụng khác và để một ứng dụng truy cập vào các dịch vụ của hệ thống:
Đó là nội dung cơ bản về cách mà một ứng dụng Android tồn tại trong hệ thống. Phần còn lại của tài liệu này giới thiệu với bạn về:
Thành phần của ứng dụng là những khối dựng thiết yếu của một ứng dụng Android. Mỗi thành phần là một điểm khác nhau mà qua đó hệ thống có thể vào ứng dụng của bạn. Không phải tất cả thành phần đều là các điểm nhập thực tế cho người dùng và một số phụ thuộc vào nhau, nhưng mỗi thành phần tồn tại như một thực thể riêng và đóng một vai trò riêng—mỗi thành phần là một khối dựng duy nhất giúp định nghĩa hành vi chung của ứng dụng của bạn.
Có bốn loại thành phần ứng dụng khác nhau. Mỗi loại có một mục đích riêng và có một vòng đời riêng, xác định cách thành phần được tạo lập và hủy.
Sau đây là bốn loại thành phần ứng dụng:
Hoạt động được triển khai như một lớp con của {@link android.app.Activity} và bạn có thể tìm hiểu thêm về nó trong hướng dẫn dành cho nhà phát triển Hoạt động .
Dịch vụ được triển khai như một lớp con của {@link android.app.Service} và bạn có thể tìm hiểu thêm về nó trong hướng dẫn cho nhà phát triển Dịch vụ .
Trình cung cấp nội dung cũng hữu ích với việc đọc và ghi dữ liệu riêng tư đối với ứng dụng của bạn và không được chia sẻ. Ví dụ, ứng dụng mẫu Note Pad sử dụng một trình cung cấp nội dung để lưu các ghi chú.
Trình cung cấp nội dung được triển khai như một lớp con của {@link android.content.ContentProvider} và phải triển khai một tập các API tiêu chuẩn cho phép các ứng dụng khác thực hiện giao tác. Để biết thêm thông tin, xem hướng dẫn cho nhà phát triển Trình cung cấp Nội dung .
Hàm nhận quảng bá được triển khai như một lớp con của {@link android.content.BroadcastReceiver} và mỗi quảng bá được chuyển giao như một đối tượng {@link android.content.Intent}. Để biết thêm thông tin, hãy xem lớp {@link android.content.BroadcastReceiver}.
Một khía cạnh độc đáo trong thiết kế hệ thống Android đó là bất kỳ ứng dụng nào cũng có thể khởi động một thành phần của ứng dụng khác. Ví dụ, nếu bạn muốn người dùng chụp ảnh bằng máy ảnh của thiết bị, có thể có một ứng dụng khác có chức năng đó và ứng dụng của bạn có thể sử dụng nó thay vì phát triển một hoạt động để tự chụp ảnh. Bạn không cần tích hợp hay thậm chí là liên kết với mã từ ứng dụng của máy ảnh. Thay vào đó, bạn đơn giản có thể khởi động hoạt động đó trong ứng dụng máy ảnh có chức năng chụp ảnh. Khi hoàn thành, ảnh thậm chí được trả về ứng dụng của bạn để bạn có thể sử dụng nó. Đối với người dùng, có vẻ như máy ảnh là một bộ phận thực sự trong ứng dụng của bạn.
Khi hệ thống khởi động một thành phần, nó sẽ khởi động tiến trình cho ứng dụng đó (nếu tiến trình không đang chạy) và khởi tạo các lớp cần thiết cho thành phần. Ví dụ, nếu ứng dụng của bạn khởi động hoạt động trong ứng dụng máy ảnh có chức năng chụp ảnh, hoạt động đó sẽ chạy trong tiến trình thuộc về ứng dụng máy ảnh chứ không chạy trong tiến trình của ứng dụng của bạn. Vì thế, không như ứng dụng trên hầu hết các hệ thống khác, ứng dụng Android không có một điểm nhập duy nhất (ví dụ, không có chức năng {@code main()}).
Vì hệ thống chạy từng ứng dụng trong một tiến trình riêng với các quyền của tệp mà hạn chế truy cập vào các ứng dụng khác, ứng dụng của bạn không thể trực tiếp kích hoạt một thành phần từ một ứng dụng khác. Tuy nhiên, hệ thống Android có thể. Vì thế, để kích hoạt một thành phần trong một ứng dụng khác, bạn phải chuyển giao một thông báo tới hệ thống trong đó nêu rõ ý định của bạn để khởi động một thành phần cụ thể. Sau đó, hệ thống sẽ kích hoạt thành phần cho bạn.
Ba trong bốn loại thành phần—hoạt động, dịch vụ và hàm nhận quảng bá—sẽ được kích hoạt bằng một thông báo không đồng bộ gọi là ý định. Ý định sẽ gắn kết từng thành phần với nhau vào thời gian chạy (bạn có thể nghĩ chúng như là các hàm nhắn tin có chức năng yêu cầu một hành động từ các thành phần khác), dù thành phần đó thuộc về ứng dụng của bạn hay ứng dụng khác.
Một ý định được tạo thành bằng một đối tượng {@link android.content.Intent}, nó định nghĩa một thông báo để kích hoạt một thành phần cụ thể hoặc một loại thành phần cụ thể—tương ứng, một ý định có thể biểu thị hoặc không biểu thị.
Đối với các hoạt động và dịch vụ, ý định có chức năng định nghĩa một hành động sẽ thực hiện (ví dụ, "xem" hoặc "gửi" gì đó) và có thể chỉ định URI của dữ liệu để hành động dựa trên đó (ngoài những điều khác mà thành phần được khởi động có thể cần biết). Ví dụ, một ý định có thể truyền tải một yêu cầu để một hoạt động hiển thị một hình ảnh hay mở một trang web. Trong một số trường hợp, bạn có thể khởi động một hoạt động để nhận kết quả, trong trường hợp đó, hoạt động cũng trả về kết quả trong một {@link android.content.Intent} (ví dụ, bạn có thể phát hành một ý định để cho phép người dùng chọn một liên lạc cá nhân và yêu cầu trả nó về cho bạn—ý định trả về bao gồm một URI chỉ đến liên lạc được chọn).
Đối với hàm nhận quảng bá, ý định chỉ định nghĩa thông báo đang được quảng bá (ví dụ, một quảng bá để báo rằng pin của thiết bị yếu sẽ chỉ bao gồm một xâu hành động chỉ báo rằng "pin yếu").
Loại thành phần còn lại, trình cung cấp nội dung, không được kích hoạt bởi ý định. Thay vào đó, nó được kích hoạt khi được nhằm tới bởi một yêu cầu từ một {@link android.content.ContentResolver}. Bộ giải quyết nội dung xử lý tất cả giao tác trực tiếp với trình cung cấp nội dung sao cho thành phần mà đang thực hiện giao tác với trình cung cấp sẽ không cần mà thay vào đó gọi các phương pháp trên đối tượng {@link android.content.ContentResolver}. Điều này để lại một lớp tóm tắt giữa trình cung cấp nội dung và thành phần yêu cầu thông tin (để bảo mật).
Có các phương pháp riêng để kích hoạt từng loại thành phần:
Để biết thêm thông tin về việc sử dụng ý định, hãy xem tài liệu Ý định và Bộ lọc Ý định. Bạn cũng có thể xem thêm thông tin về việc kích hoạt các thành phần cụ thể trong những tài liệu sau: Hoạt động, Dịch vụ, {@link android.content.BroadcastReceiver} và Trình cung cấp Nội dung.
Trước khi hệ thống Android có thể khởi động một thành phần ứng dụng, hệ thống phải biết rằng thành phần đó tồn tại bằng cách đọc tệp {@code AndroidManifest.xml} của ứng dụng (tệp "bản kê khai"). Ứng dụng của bạn phải khai báo tất cả thành phần của nó trong tệp này, nó phải nằm ở gốc của thư mục dự án của ứng dụng.
Bản kê khai làm nhiều việc bên cạnh việc khai báo các thành phần của ứng dụng, chẳng hạn như:
Nhiệm vụ chính của bản kê khai là thông báo cho hệ thống về các thành phần của ứng dụng. Ví dụ, một tệp bản kê khai có thể khai báo một hoạt động như sau:
<?xml version="1.0" encoding="utf-8"?> <manifest ... > <application android:icon="@drawable/app_icon.png" ... > <activity android:name="com.example.project.ExampleActivity" android:label="@string/example_label" ... > </activity> ... </application> </manifest>
Trong phần tử <application>
, thuộc tính {@code android:icon} sẽ trỏ đến các tài nguyên cho một biểu tượng có chức năng nhận biết
ứng dụng.
Trong phần tử <activity>
,
thuộc tính {@code android:name} quy định tên lớp hoàn toàn đủ tiêu chuẩn của lớp con {@link
android.app.Activity} và các thuộc tính {@code android:label} quy định một xâu
để sử dụng làm nhãn hiển thị với người dùng đối với hoạt động.
Bạn phải khai báo tất cả thành phần của ứng dụng như sau:
<activity>
cho hoạt động<service>
cho
dịch vụ<receiver>
cho hàm nhận quảng bá<provider>
cho trình cung cấp nội dungCác hoạt động, dịch vụ và trình cung cấp nội dung mà bạn bao gồm trong nguồn của mình nhưng không khai báo trong bản kê khai sẽ không hiển thị với hệ thống và hệ quả là không bao giờ chạy được. Tuy nhiên, hàm nhận quảng bá có thể hoặc được khai báo trong bản kê khai hoặc được tạo linh hoạt trong mã (dạng đối tượng {@link android.content.BroadcastReceiver}) và được đăng ký với hệ thống bằng cách gọi {@link android.content.Context#registerReceiver registerReceiver()}.
Để tìm hiểu thêm về cách cấu trúc tệp bản kê khai cho ứng dụng của mình, hãy xem tài liệu Tệp AndroidManifest.xml .
Như đã nêu bên trên trong phần Kích hoạt các Thành phần, bạn có thể sử dụng một {@link android.content.Intent} để khởi động các hoạt động, dịch vụ và hàm nhận quảng bá. Bạn có thể làm vậy bằng cách công khai chỉ định thành phần đích (sử dụng tên lớp thành phần) trong ý định. Tuy nhiên, sức mạnh thực sự của ý định nằm trong khái niệm ý định không biểu thị. Ý định không biểu thị đơn thuần mô tả kiểu hành động cần thực hiện (và có thể có cả dữ liệu mà bạn muốn thực hiện hành động) và cho phép hệ thống tìm một thành phần trên thiết bị có khả năng thực hiện hành động và khởi động nó. Nếu có nhiều thành phần có thể thực hiện hành động được mô tả bởi ý định, khi đó người dùng chọn ý định sẽ sử dụng.
Cách hệ thống nhận biết các thành phần có khả năng hồi đáp lại một ý định là bằng cách so sánh ý định nhận được với các bộ lọc ý định được cung cấp trong tệp bản kê khai của các ứng dụng khác trên thiết bị.
Khi bạn khai báo một hoạt động trong bản kê khai ứng dụng của mình, bạn có thể tùy chọn bao gồm các bộ lọc ý định có chức năng khai báo các khả năng của hoạt động sao cho nó có thể hồi đáp lại ý định từ các ứng dụng khác. Bạn có thể khai báo một bộ lọc ý định cho thành phần của mình bằng cách thêm một phần tử {@code <intent-filter>} làm con của phần tử công khai của thành phần đó.
Ví dụ, nếu bạn đã xây dựng một ứng dụng e-mail có một hoạt động soạn e-mail mới, bạn có thể khai báo bộ lọc ý định đó để trả lời các ý định "gửi" (để gửi một e-mail mới) như sau:
<manifest ... > ... <application ... > <activity android:name="com.example.project.ComposeEmailActivity"> <intent-filter> <action android:name="android.intent.action.SEND" /> <data android:type="*/*" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>
Sau đó, nếu một ứng dụng khác tạo một ý định với hành động {@link android.content.Intent#ACTION_SEND} và chuyển nó cho {@link android.app.Activity#startActivity startActivity()}, hệ thống có thể khởi động hoạt động của bạn để người dùng có thể soạn thảo và gửi một e-mail.
Để tìm hiểu thêm về việc tạo các bộ lọc ý định, hãy xem tài liệu Ý định và Bộ lọc Ý định.
Có nhiều loại thiết bị dựa trên nền tảng Android và không phải tất cả chúng đều cung cấp các tính năng và khả năng như nhau. Để tránh việc ứng dụng của bạn bị cài đặt trên các thiết bị thiếu những tính năng mà ứng dụng của bạn cần, điều quan trọng là bạn phải định nghĩa rõ ràng một hồ sơ cho các kiểu thiết bị mà ứng dụng của bạn hỗ trợ bằng cách khai báo các yêu cầu về thiết bị và phần mềm trong tệp bản kê khai của mình. Hầu hết những khai báo này đều chỉ mang tính chất thông báo và hệ thống không đọc chúng, nhưng các dịch vụ bên ngoài như Google Play thì có đọc để cung cấp tính năng lọc cho người dùng khi họ tìm kiếm ứng dụng từ thiết bị của mình.
Ví dụ, nếu ứng dụng của bạn yêu cầu máy ảnh và sử dụng các API được giới thiệu trong Android 2.1 (API Mức 7), bạn cần khai báo những điều này như yêu cầu trong tệp bản kê khai của mình như sau:
<manifest ... > <uses-feature android:name="android.hardware.camera.any" android:required="true" /> <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> ... </manifest>
Lúc này, những thiết bị mà không có máy ảnh và có một phiên bản Android thấp hơn 2.1 sẽ không thể cài đặt ứng dụng của bạn từ Google Play.
Tuy nhiên, bạn cũng có thể khai báo rằng ứng dụng của bạn sử dụng máy ảnh, nhưng không yêu cầu nó. Trong trường hợp đó, ứng dụng của bạn phải đặt thuộc tính {@code required} thành {@code "false"} và kiểm tra tại thời gian chạy xem thiết bị có máy ảnh không và vô hiệu hóa bất kỳ tính năng máy ảnh nào cho phù hợp.
Bạn có thể tìm hiểu thêm thông tin về cách bạn có thể quản lý tính tương thích của ứng dụng của bạn với các thiết bị khác nhau trong tài liệu Tính tương thích với Thiết bị .
Một ứng dụng Android được soạn không chỉ có mã—nó còn yêu cầu các tài nguyên tách riêng với mã nguồn, chẳng hạn như hình ảnh, tệp âm thanh và bất kỳ thứ gì liên quan tới trình chiếu trực quan của ứng dụng. Ví dụ, bạn nên định nghĩa các hoạt cảnh, menu, kiểu, màu sắc, và bố trí của giao diện người dùng của hoạt động bằng các tệp XML. Việc sử dụng các tài nguyên ứng dụng giúp dễ dàng cập nhật các đặc điểm khác nhau trong ứng dụng của bạn mà không sửa đổi mã và—bằng cách cung cấp các tập hợp tài nguyên thay thế—cho phép bạn tối ưu hóa ứng dụng của mình cho nhiều loại cấu hình thiết bị (chẳng hạn như ngôn ngữ và kích cỡ màn hình khác nhau).
Đối với mọi tài nguyên mà bạn bao gồm trong dự án Android của mình, bộ công cụ xây dựng SDK định nghĩa một ID số nguyên duy nhất mà bạn có thể sử dụng để tham chiếu tài nguyên từ mã ứng dụng của mình hoặc từ các tài nguyên khác được định nghĩa trong XML. Ví dụ, nếu ứng dụng của bạn chứa một tệp hình ảnh có tên {@code logo.png} (được lưu trong thư mục {@code res/drawable/}), bộ công cụ SDK sẽ khởi tạo một ID tài nguyên đặt tên là {@code R.drawable.logo} mà bạn có thể sử dụng để tham chiếu hình ảnh và chèn nó vào trong giao diện người dùng của mình.
Một trong những khía cạnh quan trọng nhất của việc cung cấp tài nguyên tách riêng với mã nguồn của bạn là khả năng cho phép bạn cung cấp các tài nguyên thay thế cho các cấu hình thiết bị khác nhau. Ví dụ, bằng cách định nghĩa các xâu UI trong XML, bạn có thể biên dịch xâu sang các ngôn ngữ khác và lưu các xâu đó vào tệp riêng. Sau đó, dựa vào một hạn định ngôn ngữ mà bạn nối với tên của thư mục tài nguyên (chẳng hạn như {@code res/values-fr/} đối với các giá trị xâu tiếng Pháp) và thiết đặt ngôn ngữ của người dùng, hệ thống Android sẽ áp dụng các xâu ngôn ngữ phù hợp cho UI của bạn.
Android hỗ trợ nhiều hạn định khác nhau cho các tài nguyên thay thế của bạn. Hạn định là một xâu ngắn mà bạn bao gồm trong tên của các thư mục tài nguyên của mình nhằm định nghĩa cấu hình thiết bị cho những tài nguyên đó nên được sử dụng. Lấy một ví dụ khác, bạn nên thường xuyên tạo các bố trí khác nhau cho hoạt động của mình, tùy vào hướng và kích cỡ màn hình của thiết bị. Ví dụ, khi màn hình thiết bị ở hướng đứng (cao), bạn có thể muốn một bố trí có các nút thẳng đứng, nhưng khi màn hình ở hướng khổ ngang (rộng), các nút nên được căn ngang. Để thay đổi bố trí tùy vào hướng, bạn có thể định nghĩa hai bố trí khác nhau và áp dụng hạn định phù hợp cho tên thư mục của từng bố trí. Sau đó, hệ thống sẽ tự động áp dụng bố trí phù hợp tùy thuộc vào hướng hiện tại của thiết bị.
Để biết thêm thông tin về các loại tài nguyên khác nhau mà bạn có thể bao gồm trong ứng dụng của mình và cách tạo các tài nguyên thay thế cho những cấu hình thiết bị khác nhau, hãy đọc Cung cấp Tài nguyên.