page.title=Phân đoạn parent.title=Hoạt động parent.link=activities.html @jd:body

Trong tài liệu này

  1. Triết lý Thiết kế
  2. Tạo một Phân đoạn
    1. Thêm một giao diện người dùng
    2. Thêm một phân đoạn vào một hoạt động
  3. Quản lý Phân đoạn
  4. Thực hiện Giao tác Phân đoạn
  5. Giao tiếp với Hoạt động
    1. Tạo gọi lại sự kiện cho hoạt động
    2. Thêm mục vào Thanh Hành động
  6. Xử lý Vòng đời của Phân đoạn
    1. Phối hợp với vòng đời của hoạt động
  7. Ví dụ

Lớp khóa

  1. {@link android.app.Fragment}
  2. {@link android.app.FragmentManager}
  3. {@link android.app.FragmentTransaction}

Xem thêm

  1. Xây dựng một UI Động bằng các Phân đoạn
  2. Hỗ trợ Máy tính bảng và Thiết bị cầm tay

{@link android.app.Fragment} biểu diễn một hành vi hay một phần giao diện người dùng trong một {@link android.app.Activity}. Bạn có thể kết hợp nhiều phân đoạn trong một hoạt động duy nhất để xây dựng một UI nhiều bảng và sử dụng lại phân đoạn trong nhiều hoạt động. Bạn có thể coi phân đoạn như là một phần mô-đun của một hoạt động, có vòng đời của chính nó, nhận các sự kiện đầu vào của chính nó, và bạn có thể thêm hoặc gỡ bỏ trong khi hoạt động đang chạy (kiểu như một "hoạt động con" mà bạn có thể sử dụng lại trong các hoạt động khác nhau).

Phân đoạn phải luôn được nhúng trong một hoạt động và vòng đời của phân đoạn bị ảnh hưởng trực tiếp bởi vòng đời của hoạt động chủ. Ví dụ, khi hoạt động bị tạm dừng, tất cả phân đoạn trong nó cũng vậy, và khi hoạt động bị hủy, tất cả phân đoạn cũng vậy. Tuy nhiên, trong khi một hoạt động đang chạy (nó ở trong trạng thái vòng đời được tiếp tục), bạn có thể thao tác từng phân đoạn độc lập, chẳng hạn như thêm hay xóa chúng. Khi bạn thực hiện một giao tác phân đoạn, bạn cũng có thể thêm nó vào một ngăn xếp được quản lý bởi hoạt động đó—từng mục nhập vào ngăn xếp trong hoạt động là một bản ghi giao tác phân đoạn đã xảy ra. Ngăn xếp cho phép người dùng đảo ngược một giao tác phân đoạn (điều hướng ngược lại), bằng cách nhấn nút Quay lại.

Khi bạn thêm một phân đoạn như một phần trong bố trí hoạt động của mình, nó sẽ ở trong một {@link android.view.ViewGroup} bên trong phân cấp dạng xem của hoạt động đó và phân đoạn này sẽ định nghĩa bố trí dạng xem của chính nó. Bạn có thể chèn một phân đoạn vào bố trí hoạt động của mình bằng cách khai báo phân đoạn trong tệp bố trí của hoạt động, dưới dạng một phần tử {@code <fragment>}, hoặc từ mã ứng dụng của bạn bằng cách thêm nó vào một {@link android.view.ViewGroup} hiện hữu. Tuy nhiên, không bắt buộc phải có một phân đoạn là một bộ phận của bố trí hoạt động ; bạn cũng có thể sử dụng một phân đoạn mà không cần UI của chính nó như một trình thực hiện vô hình cho hoạt động .

Tài liệu này mô tả cách xây dựng ứng dụng của bạn để sử dụng phân đoạn, bao gồm cách các phân đoạn có thể duy trì trạng thái của chúng khi được thêm vào ngăn xếp của hoạt động, chia sẻ các sự kiện với hoạt động và các phân đoạn khác trong hoạt động, đóng góp vào thanh hành động của hoạt động và nhiều thông tin khác.

Triết lý Thiết kế

Android giới thiệu phân đoạn trong phiên bản Android 3.0 (API mức 11), chủ yếu nhằm hỗ trợ các thiết kế UI động và linh hoạt hơn trên màn hình lớn, chẳng hạn như máy tính bảng. Vì màn hình của máy tính bảng lớn hơn nhiều màn hình của thiết bị cầm tay, có nhiều khoảng trống hơn để kết hợp và trao đổi các thành phần UI. Phân đoạn cho phép những thiết kế như vậy mà không cần bạn phải quản lý những thay đổi phức tạp về phân cấp dạng xem. Bằng cách chia bố trí của một hoạt động thành các phân đoạn, bạn có thể sửa đổi diện mạo của hoạt động vào thời gian chạy và giữ những thay đổi đó trong một ngăn xếp được quản lý bởi hoạt động.

Ví dụ, một ứng dụng tin tức có thể sử dụng một phân đoạn để hiển thị một danh sách bài viết ở bên trái và một phân đoạn khác để hiển thị một bài viết ở bên phải—cả hai phân đoạn đều xuất hiện trong một hoạt động, bên cạnh nhau, và từng phân đoạn có tập phương pháp gọi lại vòng đời riêng và xử lý các sự kiện nhập liệu người dùng riêng của mình. Vì thế, thay vì sử dụng một hoạt động để chọn một bài viết và một hoạt động khác để đọc bài viết, người dùng có thể chọn một bài viết và đọc nó trong cùng hoạt động, như được minh họa trong bố trí máy tính bảng trong hình 1.

Bạn nên thiết kế từng phân đoạn như một thành phần hoạt động dạng mô-đun và có thể sử dụng lại. Đó là bởi mỗi phân đoạn sẽ định nghĩa bố trí và hành vi của chính nó với các phương pháp gọi lại vòng đời của chính nó, bạn có thể bao gồm một phân đoạn trong nhiều hoạt động, vì thế bạn nên thiết kế để tái sử dụng và tránh trực tiếp thao tác một phân đoạn từ một phân đoạn khác. Điều này đặc biệt quan trọng vì một phân đoạn mô-đun cho phép bạn thay đổi kết hợp phân đoạn của mình cho các kích cỡ màn hình khác nhau. Khi thiết kế ứng dụng của bạn để hỗ trợ cả máy tính bảng và thiết bị cầm tay, bạn có thể sử dụng lại phân đoạn của mình trong các cấu hình bố trí khác nhau nhằm tối ưu hóa trải nghiệm người dùng dựa trên không gian màn hình có sẵn. Ví dụ, trên một thiết bị cầm tay, có thể cần phải tách riêng các phân đoạn để cung cấp một UI đơn bảng khi mà không thể làm vừa khít nhiều hơn một phân đoạn trong cùng hoạt động.

Hình 1. Ví dụ về cách hai mô-đun UI được định nghĩa bởi các phân đoạn có thể được kết hợp thành một hoạt động đối với thiết kế máy tính bảng, nhưng được tách riêng đối với thiết kế thiết bị cầm tay.

Ví dụ—để tiếp tục với ví dụ về ứng dụng tin tức—ứng dụng có thể nhúng hai phân đoạn trong Hoạt động A, khi đang chạy trên một thiết bị có kích cỡ máy tính bảng. Tuy nhiên, trên một màn hình kích cỡ thiết bị cầm tay, không có đủ khoảng trống cho cả hai phân đoạn, vì thế Hoạt động A chỉ bao gồm phân đoạn cho danh sách bài viết, và khi người dùng chọn một bài viết, nó sẽ khởi động Hoạt động B, hoạt động này chứa phân đoạn thứ hai là đọc bài viết. Vì thế, ứng dụng hỗ trợ cả máy tính bảng và thiết bị cầm tay bằng cách sử dụng lại các phân đoạn theo các cách kết hợp khác nhau như được minh họa trong hình 1.

Để biết thêm thông tin về việc thiết kế ứng dụng của bạn bằng các cách kết hợp phân đoạn khác nhau cho cấu hình màn hình khác nhau, hãy xem hướng dẫn Hỗ trợ Máy tính bảng và Thiết bị cầm tay.

Tạo một Phân đoạn

Hình 2. Vòng đời của một phân đoạn (trong khi hoạt động của nó đang chạy).

Để tạo một phân đoạn, bạn phải tạo một lớp con của {@link android.app.Fragment} (hoặc một lớp con hiện tại của nó). Lớp {@link android.app.Fragment} có mã trông rất giống một {@link android.app.Activity}. Nó chứa các phương pháp gọi lại tương tự như hoạt động, chẳng hạn như {@link android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onStart onStart()}, {@link android.app.Fragment#onPause onPause()}, và {@link android.app.Fragment#onStop onStop()}. Trên thực tế, nếu bạn đang chuyển đổi một ứng dụng Android hiện tại để sử dụng các phân đoạn, bạn có thể chỉ cần di chuyển mã khỏi các phương pháp gọi lại của hoạt động của bạn vào các phương pháp gọi lại tương ứng của phân đoạn của bạn.

Thường thì ít nhất bạn nên triển khai các phương pháp vòng đời sau:

{@link android.app.Fragment#onCreate onCreate()}
Hệ thống sẽ gọi phương pháp này khi tạo phân đoạn. Trong triển khai của mình, bạn nên khởi tạo các thành phần thiết yếu của phân đoạn mà bạn muốn giữ lại khi phân đoạn bị tạm dừng hoặc dừng hẳn, sau đó tiếp tục.
{@link android.app.Fragment#onCreateView onCreateView()}
Hệ thống sẽ gọi phương pháp này khi đến lúc phân đoạn vẽ giao diện người dùng của nó lần đầu tiên. Để vẽ một UI cho phân đoạn của mình, bạn phải trả về một {@link android.view.View} từ phương pháp này, đây là gốc của bố trí phân đoạn của bạn. Bạn có thể trả về giá trị rỗng nếu phân đoạn không cung cấp UI.
{@link android.app.Activity#onPause onPause()}
Hệ thống gọi phương pháp này là dấu hiệu đầu tiên về việc người dùng đang rời khỏi phân đoạn (mặc dù không phải lúc nào cũng có nghĩa rằng phân đoạn đang bị hủy). Trường hợp này thường là khi bạn định thực hiện bất kỳ thay đổi nào vẫn cần có hiệu lực ngoài phiên của người dùng hiện thời (vì người dùng có thể không quay lại).

Phần lớn ứng dụng nên triển khai ít nhất ba phương pháp sau đối với mọi phân đoạn, nhưng có một vài phương pháp gọi lại khác mà bạn cũng nên sử dụng để xử lý các giai đoạn khác nhau trong vòng đời của phân đoạn. Tất cả phương pháp gọi lại vòng đời được đề cập chi tiết hơn trong phần về Xử lý Vòng đời của Phân đoạn.

Cũng có một vài lớp con mà bạn có thể muốn mở rộng thay vì lớp cơ bản {@link android.app.Fragment}:

{@link android.app.DialogFragment}
Hiển thị một hộp thoại trôi nổi. Sử dụng lớp này để tạo một hộp thoại là một phương án hay cho việc sử dụng các phương pháp trình trợ giúp hộp thoại trong lớp {@link android.app.Activity}, vì bạn có thể kết hợp một hộp thoại phân đoạn vào ngăn xếp của các phân đoạn được quản lý bởi hoạt động, cho phép người dùng trả về một phân đoạn bị bỏ.
{@link android.app.ListFragment}
Hiển thị một danh sách các mục được quản lý bởi một trình điều hợp (chẳng hạn như một {@link android.widget.SimpleCursorAdapter}), tương tự như {@link android.app.ListActivity}. Nó cung cấp một vài phương pháp để quản lý một dạng xem danh sách, chẳng hạn như phương pháp gọi lại {@link android.app.ListFragment#onListItemClick(ListView,View,int,long) onListItemClick()} để xử lý các sự kiện nhấp.
{@link android.preference.PreferenceFragment}
Hiển thị một phân cấp các đối tượng {@link android.preference.Preference} dưới dạng một danh sách, tương tự như {@link android.preference.PreferenceActivity}. Điều này hữu ích khi tạo một hoạt động "thiết đặt" cho ứng dụng của bạn.

Thêm một giao diện người dùng

Phân đoạn thường được sử dụng như một phần giao diện người dùng của hoạt động và đóng góp bố trí của chính nó cho hoạt động.

Để cung cấp một bố trí cho một phân đoạn, bạn phải triển khai phương pháp gọi lại {@link android.app.Fragment#onCreateView onCreateView()}, phương pháp này được hệ thống Android gọi khi đến lúc phân đoạn vẽ bố trí của nó. Việc bạn triển khai phương pháp này phải trả về một {@link android.view.View} là phần gốc cho bố trí phân đoạn của bạn.

Lưu ý: Nếu phân đoạn của bạn là một lớp con của {@link android.app.ListFragment}, triển khai mặc định sẽ trả về một {@link android.widget.ListView} từ {@link android.app.Fragment#onCreateView onCreateView()}, vì thế bạn không cần triển khai nó.

Để trả về một bố trí từ {@link android.app.Fragment#onCreateView onCreateView()}, bạn có thể bung nó từ một tài nguyên bố trí được định nghĩa trong XML. Để giúp bạn làm vậy, {@link android.app.Fragment#onCreateView onCreateView()} cung cấp một đối tượng {@link android.view.LayoutInflater}.

Ví dụ, sau đây là một lớp con của {@link android.app.Fragment} với chức năng nạp một bố trí từ tệp {@code example_fragment.xml}:

public static class ExampleFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.example_fragment, container, false);
    }
}

Tham số {@code container} được chuyển tới {@link android.app.Fragment#onCreateView onCreateView()} là {@link android.view.ViewGroup} mẹ (tức bố trí của hoạt động), trong đó bố trí phân đoạn của bạn sẽ được chèn vào. Tham số {@code savedInstanceState} là một {@link android.os.Bundle} có chức năng cung cấp dữ liệu về thực thể trước đó của phân đoạn, nếu phân đoạn đang được tiếp tục (việc khôi phục trạng thái được bàn kỹ hơn trong phần về Xử lý Vòng đời của Phân đoạn).

Phương pháp {@link android.view.LayoutInflater#inflate(int,ViewGroup,boolean) inflate()} có ba tham đối:

Giờ bạn đã thấy cách tạo một phân đoạn nhằm cung cấp một bố trí. Tiếp theo, bạn cần thêm phân đoạn vào hoạt động của mình.

Thêm một phân đoạn vào một hoạt động

Thường thì một phân đoạn đóng góp một phần UI vào hoạt động chủ, nó được nhúng như một phần trong phân cấp dạng xem tổng thể của hoạt động. Có hai cách mà bạn có thể thêm một phân đoạn vào bố trí của hoạt động:

Thêm một phân đoạn không có UI

Các ví dụ nêu trên cho biết cách thêm một phân đoạn vào hoạt động của bạn để cung cấp một UI. Tuy nhiên, bạn cũng có thể sử dụng một phân đoạn để cung cấp một hành vi chạy ngầm cho hoạt động mà không cần đưa UI bổ sung.

Để thêm một phân đoạn không có UI, hãy thêm phân đoạn từ hoạt động đang bằng cách sử dụng {@link android.app.FragmentTransaction#add(Fragment,String)} (cung cấp một "tag" xâu duy nhất cho phân đoạn , thay vì một ID dạng xem). Làm vậy sẽ thêm phân đoạn, nhưng vì không liên kết với một dạng xem trong bố trí hoạt động, nó sẽ không nhận được lệnh gọi tới {@link android.app.Fragment#onCreateView onCreateView()}. Vì thế, bạn không cần triển khai phương pháp đó.

Việc cung cấp tag xâu cho phân đoạn không chỉ áp dụng cho các phân đoạn không có UI—bạn cũng có thể cung cấp tag xâu cho phân đoạn có UI—nhưng nếu phân đoạn không có UI, khi đó, tag xâu là cách duy nhất để nhận biết nó. Nếu sau này bạn muốn nhận phân đoạn từ hoạt động, bạn cần sử dụng {@link android.app.FragmentManager#findFragmentByTag findFragmentByTag()}.

Để biết ví dụ về hoạt động sử dụng phân đoạn như một trình thực hiện nền, không có UI, hãy xem mẫu {@code FragmentRetainInstance.java}, mẫu này có trong các mẫu SDK (có sẵn thông qua Trình quản lý SDK Android) và nằm trên hệ thống của bạn như là <sdk_root>/APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java.

Quản lý Phân đoạn

Để quản lý các phân đoạn trong hoạt động của mình, bạn cần sử dụng {@link android.app.FragmentManager}. Để có nó, hãy gọi {@link android.app.Activity#getFragmentManager()} từ hoạt động của bạn.

Một số việc bạn có thể làm với {@link android.app.FragmentManager} bao gồm:

Để biết thêm thông tin về những phương pháp này và phương pháp khác, hãy tham khảo tài liệu lớp {@link android.app.FragmentManager}.

Như minh họa trong phần trước, bạn cũng có thể sử dụng {@link android.app.FragmentManager} để mở một {@link android.app.FragmentTransaction}, nó cho phép bạn thực hiện các giao tác, ví dụ như thêm hoặc gỡ bỏ phân đoạn.

Thực hiện Giao tác Phân đoạn

Một tính năng tuyệt vời khi sử dụng phân đoạn trong hoạt động của bạn đó là khả năng thêm, gỡ bỏ, thay thế, và thực hiện các hành động khác với chúng, để hồi đáp lại tương tác của người dùng. Mỗi tập hợp thay đổi mà bạn thực thi cho hoạt động được gọi là một giao tác và bạn có thể thực hiện một giao tác bằng cách sử dụng các API trong {@link android.app.FragmentTransaction}. Bạn cũng có thể lưu từng giao tác vào một ngăn xếp được quản lý bởi hoạt động, cho phép người dùng điều hướng ngược lại thông qua những thay đổi phân đoạn (tương tự như điều hướng ngược lại thông qua hoạt động).

Bạn có thể thu được một thực thể của {@link android.app.FragmentTransaction} từ {@link android.app.FragmentManager} như sau:

FragmentManager fragmentManager = {@link android.app.Activity#getFragmentManager()};
FragmentTransaction fragmentTransaction = fragmentManager.{@link android.app.FragmentManager#beginTransaction()};

Mỗi giao tác là một tập hợp những thay đổi mà bạn muốn thực hiện tại cùng thời điểm. Bạn có thể thiết lập tất cả thay đổi mà mình muốn thực hiện đối với một giao tác cho trước bằng cách sử dụng các phương pháp như {@link android.app.FragmentTransaction#add add()}, {@link android.app.FragmentTransaction#remove remove()}, và {@link android.app.FragmentTransaction#replace replace()}. Sau đó, để áp dụng giao tác cho hoạt động, bạn phải gọi {@link android.app.FragmentTransaction#commit()}.

Trước khi bạn gọi {@link android.app.FragmentTransaction#commit()}, tuy nhiên, bạn có thể muốn gọi {@link android.app.FragmentTransaction#addToBackStack addToBackStack()}, để thêm giao tác vào một ngăn xếp của các giao tác phân đoạn. Ngăn xếp này được quản lý bởi hoạt động và cho phép người dùng trở về trạng thái phân đoạn trước đó, bằng cách nhấp nút Quay lại.

Ví dụ, sau đây là cách bạn có thể thay thế phân đoạn này bằng phân đoạn khác, và giữ nguyên trạng thái trước đó của ngăn xếp:

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

Trong ví dụ này, {@code newFragment} thay thế mọi phân đoạn (nếu có) hiện đang ở trong bộ chứa bố trí được nhận biết bởi ID {@code R.id.fragment_container}. Bằng cách gọi {@link android.app.FragmentTransaction#addToBackStack addToBackStack()}, giao tác thay thế được lưu vào ngăn xếp, vì thế người dùng có thể đảo ngược giao tác và mang giao tác trước đó trở lại bằng cách nhấn nút Quay lại.

Nếu bạn thêm nhiều thay đổi vào giao tác (chẳng hạn như một {@link android.app.FragmentTransaction#add add()} khác hoặc {@link android.app.FragmentTransaction#remove remove()}) và gọi {@link android.app.FragmentTransaction#addToBackStack addToBackStack()}, khi đó, tất cả thay đổi được áp dụng trước khi bạn gọi {@link android.app.FragmentTransaction#commit commit()} đều được thêm vào ngăn xếp như một giao tác riêng lẻ và nút Quay lại sẽ đảo ngược tất cả cùng nhau.

Thứ tự mà bạn thêm thay đổi vào một {@link android.app.FragmentTransaction} không quan trọng, ngoại trừ:

Nếu bạn không gọi {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} khi thực hiện một giao tác để xóa một phân đoạn, khi đó, phân đoạn đó sẽ bị hủy khi giao tác được thực hiện và người dùng không thể điều hướng trở lại nó. Trong khi đó, nếu bạn gọi {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} khi gỡ bỏ một phân đoạn, khi đó phân đoạn bị dừng và sẽ được khôi phục nếu người dùng điều hướng trở lại.

Mẹo: Với mỗi giao tác phân đoạn, bạn có thể áp dụng một hoạt ảnh chuyển tiếp bằng cách gọi {@link android.app.FragmentTransaction#setTransition setTransition()} trước khi thực thi.

Việc gọi {@link android.app.FragmentTransaction#commit()} không thực hiện giao tác ngay lập tức. Thay vào đó, nó lập lịch biểu để chạy trên luồng UI của hoạt động (luồng "chính") ngay khi luồng có thể làm vậy. Tuy nhiên, nếu cần, bạn có thể gọi {@link android.app.FragmentManager#executePendingTransactions()} từ luồng UI của mình để ngay lập tức thực hiện các giao tác được gửi bởi {@link android.app.FragmentTransaction#commit()}. Làm vậy thường không cần thiết trừ khi giao tác đó là phụ thuộc cho các tác vụ ở những luồng khác.

Chú ý: Bạn có thể thực thi một giao tác bằng cách sử dụng {@link android.app.FragmentTransaction#commit commit()} chỉ trước khi hoạt động lưu trạng thái của nó (khi người dùng rời khỏi hoạt động). Nếu bạn định thực thi sau thời điểm đó sẽ phát sinh một lỗi ngoại lệ. Nguyên nhân là vì trạng thái sau khi thực thi có thể bị mất nếu hoạt động cần được khôi phục. Đối với những trường hợp mà bạn có thể mất thực thi, hãy sử dụng {@link android.app.FragmentTransaction#commitAllowingStateLoss()}.

Giao tiếp với Hoạt động

Mặc dù {@link android.app.Fragment} được triển khai như một đối tượng độc lập với {@link android.app.Activity} và có thể được sử dụng bên trong nhiều hoạt động, một thực thể đã cho của phân đoạn sẽ được gắn kết trực tiếp với hoạt động chứa nó.

Cụ thể, phân đoạn có thể truy cập thực thể {@link android.app.Activity} bằng {@link android.app.Fragment#getActivity()} và dễ dàng thực hiện các tác vụ như tìm một dạng xem trong bố trí hoạt động:

View listView = {@link android.app.Fragment#getActivity()}.{@link android.app.Activity#findViewById findViewById}(R.id.list);

Tương tự, hoạt động của bạn có thể gọi ra các phương pháp trong phân đoạn bằng cách thu được một tham chiếu tới {@link android.app.Fragment} từ {@link android.app.FragmentManager}, bằng cách sử dụng {@link android.app.FragmentManager#findFragmentById findFragmentById()} hoặc {@link android.app.FragmentManager#findFragmentByTag findFragmentByTag()}. Ví dụ:

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);

Tạo gọi lại sự kiện cho hoạt động

Trong một số trường hợp, bạn có thể cần một phân đoạn để chia sẻ sự kiện với hoạt động. Một cách hay để làm điều này đó là định nghĩa một giao diện gọi lại bên trong phân đoạn và yêu cầu hoạt động chủ triển khai nó. Khi hoạt động nhận được một lệnh gọi lại thông qua giao diện, nó có thể chia sẻ thông tin với các phân đoạn khác trong bố trí nếu cần.

Ví dụ, nếu một ứng dụng tin tức có hai phân đoạn trong một hoạt động—một để hiển thị danh sách bài viết (phân đoạn A) và một để hiển thị một bài viết (phân đoạn B)—khi đó, phân đoạn A phải thông báo với hoạt động khi nào thì một mục danh sách được chọn để nó có thể yêu cầu phân đoạn B hiển thị bài viết đó. Trong trường hợp này, giao diện {@code OnArticleSelectedListener} sẽ được khai báo bên trong phân đoạn A:

public static class FragmentA extends ListFragment {
    ...
    // Container Activity must implement this interface
    public interface OnArticleSelectedListener {
        public void onArticleSelected(Uri articleUri);
    }
    ...
}

Khi đó, hoạt động lưu trữ phân đoạn sẽ triển khai giao diện {@code OnArticleSelectedListener} và khống chế {@code onArticleSelected()} để thông báo với phân đoạn B về sự kiện từ phân đoạn A. Để đảm bảo rằng hoạt động chủ triển khai giao diện này, phương pháp gọi lại {@link android.app.Fragment#onAttach onAttach()} của phân đoạn A (mà hệ thống gọi khi thêm phân đoạn vào hoạt động) sẽ khởi tạo một thực thể của {@code OnArticleSelectedListener} bằng cách đổi kiểu {@link android.app.Activity} mà được chuyển vào {@link android.app.Fragment#onAttach onAttach()}:

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnArticleSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
        }
    }
    ...
}

Nếu hoạt động chưa triển khai giao diện, khi đó phân đoạn sẽ đưa ra lỗi {@link java.lang.ClassCastException}. Nếu thành công, thành viên {@code mListener} giữ một tham chiếu tới triển khai {@code OnArticleSelectedListener}của hoạt động, sao cho phân đoạn A có thể chia sẻ sự kiện với hoạt động bằng cách gọi các phương pháp được định nghĩa bởi giao diện {@code OnArticleSelectedListener}. Ví dụ, nếu phân đoạn A là một phần mở rộng của {@link android.app.ListFragment}, mỗi lần người dùng nhấp vào một mục danh sách, hệ thống sẽ gọi ra {@link android.app.ListFragment#onListItemClick onListItemClick()} trong phân đoạn, và nó lại gọi {@code onArticleSelected()} để chia sẻ sự kiện với hoạt động:

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    ...
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Append the clicked item's row ID with the content provider Uri
        Uri noteUri = ContentUris.{@link android.content.ContentUris#withAppendedId withAppendedId}(ArticleColumns.CONTENT_URI, id);
        // Send the event and Uri to the host activity
        mListener.onArticleSelected(noteUri);
    }
    ...
}

Tham số {@code id} được chuyển vào {@link android.app.ListFragment#onListItemClick onListItemClick()} là ID hàng của mục được nhấp, nó được sử dụng bởi hoạt động (hoặc phân đoạn kia) để tải bài viết từ {@link android.content.ContentProvider} của ứng dụng.

Bạn có thể xem thêm thông tin về cách sử dụng một trình cung cấp nội dung trong tài liệu Trình cung cấp Nội dung.

Thêm mục vào Thanh Hành động

Phân đoạn của bạn có thể đóng góp các mục menu vào Menu Tùy chọn của hoạt động (và tiếp đó là cả Thanh Hành động) bằng cách triển khai {@link android.app.Fragment#onCreateOptionsMenu(Menu,MenuInflater) onCreateOptionsMenu()}. Tuy nhiên, để phương pháp này nhận lệnh gọi, bạn phải gọi {@link android.app.Fragment#setHasOptionsMenu(boolean) setHasOptionsMenu()} trong khi {@link android.app.Fragment#onCreate(Bundle) onCreate()}, để cho biết rằng phân đoạn sẽ muốn thêm mục vào Menu Tùy chọn (nếu không, phân đoạn sẽ không nhận được lệnh gọi tới {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()}).

Bất kỳ mục nào mà bạn thêm vào Menu Tùy chọn sau đó từ phân đoạn đều được nối với các mục menu hiện tại. Phân đoạn cũng nhận các lệnh gọi lại tới {@link android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} khi một mục menu được chọn.

Bạn cũng có thể đăng ký một dạng xem trong bố trí phân đoạn của mình để cung cấp một menu ngữ cảnh bằng cách gọi {@link android.app.Fragment#registerForContextMenu(View) registerForContextMenu()}. Khi người dùng mở menu ngữ cảnh, phân đoạn nhận một lệnh gọi tới {@link android.app.Fragment#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo) onCreateContextMenu()}. Khi người dùng chọn một mục, phân đoạn nhận được một lệnh gọi tới {@link android.app.Fragment#onContextItemSelected(MenuItem) onContextItemSelected()}.

Lưu ý: Mặc dù phân đoạn của bạn nhận được một lệnh gọi khi chọn mục đối với từng mục menu mà nó thêm, trước tiên hoạt động sẽ nhận phương pháp gọi lại tương ứng khi người dùng chọn một mục menu. Nếu việc triển khai gọi lại khi chọn mục của hoạt động không xử lý mục được chọn, khi đó sự kiện được chuyển sang phương pháp gọi lại của phân đoạn. Điều này đúng đối với Menu Tùy chọn và các menu ngữ cảnh.

Để biết thêm thông tin về các menu, xem các hướng dẫn cho nhà phát triển MenuThanh Hành động.

Xử lý Vòng đời của Phân đoạn

Hình 3. Ảnh hưởng của vòng đời hoạt động tới vòng đời của phân đoạn.

Việc quản lý vòng đời của một phân đoạn rất giống với quản lý vòng đời của một hoạt động. Giống như hoạt động, phân đoạn có thể tồn tại ở ba trạng thái:

Tiếp tục
Phân đoạn hiển thị trong hoạt động đang chạy.
Tạm dừng
Một hoạt động khác ở trong tiền cảnh và có tiêu điểm, nhưng hoạt động mà phân đoạn này nằm trong vẫn hiển thị (hoạt động tiền cảnh mờ một phần hoặc không che phủ toàn bộ màn hình).
Dừng
Phân đoạn không hiển thị. Hoặc là hoạt động chủ đã bị dừng hoặc phân đoạn đã được gỡ bỏ khỏi hoạt động, nhưng được thêm vào ngăn xếp. Phân đoạn dừng vẫn còn hoạt động (tất cả thông tin về trạng thái và thành viên đều được hệ thống giữ lại). Tuy nhiên, nó không còn hiển thị với người dùng nữa và sẽ bị tắt bỏ nếu hoạt động bị tắt bỏ.

Cũng như một hoạt động, bạn có thể giữ lại trạng thái của một phân đoạn bằng cách sử dụng {@link android.os.Bundle}, trong trường hợp tiến trình của hoạt động bị tắt bỏ và bạn cần khôi phục trạng thái của phân đoạn khi hoạt động được tạo lại. Bạn có thể lưu trạng thái trong phương pháp gọi lại {@link android.app.Fragment#onSaveInstanceState onSaveInstanceState()} của phân đoạn và khôi phục nó trong hoặc {@link android.app.Fragment#onCreate onCreate()}, {@link android.app.Fragment#onCreateView onCreateView()}, hoặc {@link android.app.Fragment#onActivityCreated onActivityCreated()}. Để biết thêm thông tin về việc lưu trạng thái, xem tài liệu Hoạt động .

Sự khác nhau quan trọng nhất trong vòng đời giữa một hoạt động và một phân đoạn đó là cách chúng được lưu trữ trong ngăn xếp tương ứng. Hoạt động được đặt vào một ngăn xếp gồm nhiều hoạt động , được quản lý bởi hệ thống theo mặc định khi bị dừng (sao cho người dùng có thể điều hướng lại nó bằng nút Quay lại như được đề cập trong Tác vụ và Ngăn xếp). Tuy nhiên, phân đoạn chỉ được đặt vào một ngăn xếp do hoạt động chủ quản lý khi bạn yêu cầu rõ ràng rằng trường hợp đó phải được lưu bằng cách gọi {@link android.app.FragmentTransaction#addToBackStack(String) addToBackStack()} trong một giao tác gỡ bỏ phân đoạn.

Nếu không thì việc quản lý vòng đời của phân đoạn rất giống với việc quản lý vòng đời của hoạt động. Vì thế, những nội dung áp dụng cho quản lý vòng đời của hoạt động cũng áp dụng cho phân đoạn. Tuy nhiên, việc mà bạn cũng cần phải hiểu đó là cách vòng đời của hoạt động ảnh hưởng tới vòng đời của phân đoạn.

Chú ý: Nếu bạn cần một đối tượng {@link android.content.Context} trong {@link android.app.Fragment}của mình, bạn có thể gọi {@link android.app.Fragment#getActivity()}. Tuy nhiên, nhớ chỉ được gọi {@link android.app.Fragment#getActivity()} khi phân đoạn được gắn với một hoạt động. Khi phân đoạn chưa được gắn, hoặc bị gỡ trong khi kết thúc vòng đời của nó, {@link android.app.Fragment#getActivity()} sẽ trả về rỗng.

Phối hợp với vòng đời của hoạt động

Vòng đời của hoạt động mà phân đoạn có ở trong đó sẽ trực tiếp ảnh hưởng tới vòng đời của phân đoạn , sao cho mỗi lệnh gọi lại vòng đời cho hoạt động đó sẽ dẫn tới một lệnh gọi lại tương tự cho từng phân đoạn. Ví dụ, khi hoạt động nhận được {@link android.app.Activity#onPause}, mỗi phân đoạn trong hoạt động sẽ nhận được {@link android.app.Fragment#onPause}.

Tuy nhiên, các phân đoạn có thêm một vài lệnh gọi lại vòng đời nhằm xử lý tương tác duy nhất với hoạt động để thực hiện các hành động như xây dựng và hủy UI của phân đoạn. Những phương pháp gọi lại bổ sung này là:

{@link android.app.Fragment#onAttach onAttach()}
Được gọi khi phân đoạn đã được liên kết với hoạt động {@link android.app.Activity} được chuyển ở đây).
{@link android.app.Fragment#onCreateView onCreateView()}
Được gọi khi tạo phân cấp dạng xem được liên kết với phân đoạn.
{@link android.app.Fragment#onActivityCreated onActivityCreated()}
Được gọi khi phương pháp {@link android.app.Activity#onCreate onCreate()} của hoạt động đã trả về.
{@link android.app.Fragment#onDestroyView onDestroyView()}
Được gọi khi phân cấp dạng xem được liên kết với phân đoạn đang được gỡ bỏ.
{@link android.app.Fragment#onDetach onDetach()}
Được gọi khi phân đoạn đang được bỏ liên kết khỏi hoạt động.

Tiến trình vòng đời của một phân đoạn, do bị ảnh hưởng bởi hoạt động chủ của nó, được minh họa bởi hình 3. Trong hình này, bạn có thể thấy cách thức mỗi trạng thái nối tiếp nhau của hoạt động sẽ xác định các phương pháp gọi lại nào mà một phân đoạn có thể nhận được. Ví dụ, khi hoạt động đã nhận được lệnh gọi lại {@link android.app.Activity#onCreate onCreate()} của nó, phân đoạn trong hoạt động sẽ nhận được không quá lệnh gọi lại {@link android.app.Fragment#onActivityCreated onActivityCreated()}.

Sau khi hoạt động đạt trạng thái tiếp tục, bạn có thể tự do thêm và gỡ bỏ phân đoạn vào hoạt động. Vì thế, chỉ trong khi hoạt động ở trạng thái tiếp tục thì vòng đời của một phân đoạn mới có thể thay đổi độc lập.

Tuy nhiên, khi hoạt động rời khỏi trạng thái tiếp tục, phân đoạn lại bị hoạt động đẩy qua vòng đời của mình.

Ví dụ

Để kết hợp mọi nội dung được đề cập trong tài liệu này, sau đây là một ví dụ về hoạt động sử dụng hai phân đoạn để tạo một bố trí hai bảng. Hoạt động bên dưới bao gồm một phân đoạn để hiển thị danh sách các vở kịch của Shakespeare và một phân đoạn khác để hiển thị tóm tắt về vở kịch khi được chọn từ danh sách. Nó cũng minh họa cách cung cấp các cấu hình phân đoạn khác nhau, dựa trên cấu hình màn hình.

Lưu ý: Mã nguồn hoàn chỉnh cho hoạt động này có sẵn trong {@code FragmentLayout.java}.

Hoạt động chính áp dụng một bố trí theo cách thông thường, trong {@link android.app.Activity#onCreate onCreate()}:

{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java main}

Bố trí được áp dụng là {@code fragment_layout.xml}:

{@sample development/samples/ApiDemos/res/layout-land/fragment_layout.xml layout}

Khi sử dụng bố trí này, hệ thống sẽ khởi tạo {@code TitlesFragment} (liệt kê tên các vở kịch) ngay khi hoạt động nạp bố trí, trong khi {@link android.widget.FrameLayout} (nơi sẽ xuất hiện phân đoạn hiển thị tóm tắt về vở kịch) chiếm khoảng trống phía bên phải của màn hình, nhưng ban đầu vẫn trống. Như bạn sẽ thấy bên dưới, mãi tới khi người dùng chọn một mục từ danh sách thì một phân đoạn mới được đặt vào {@link android.widget.FrameLayout}.

Tuy nhiên, không phải tất cả cấu hình màn hình đều đủ rộng để hiển thị cả danh sách các vở kịch và tóm tắt bên cạnh nhau. Vì thế, bố trí trên chỉ được sử dụng cho cấu hình màn hình khổ ngang bằng cách lưu nó dưới dạng {@code res/layout-land/fragment_layout.xml}.

Vì thế, khi màn hình hướng đứng, hệ thống sẽ áp dụng bố trí sau, nó được lưu tại {@code res/layout/fragment_layout.xml}:

{@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout}

Bố trí này chỉ bao gồm {@code TitlesFragment}. Điều này có nghĩa là, khi thiết bị ở hướng đứng, chỉ danh sách tên vở kịch được hiển thị. Vì thế, khi người dùng nhấp vào một mục danh sách trong cấu hình này, ứng dụng sẽ bắt đầu một hoạt động mới để hiển thị tóm tắt, thay vì tải một phân đoạn thứ hai.

Tiếp theo, bạn có thể thấy cách hoàn thành điều này trong các lớp phân đoạn. Đầu tiên là {@code TitlesFragment}, hiển thị danh sách tên các vở kịch của Shakespeare. Phân đoạn này sẽ mở rộng {@link android.app.ListFragment} và dựa vào nó để xử lý hầu hết công việc về dạng xem danh sách.

Khi bạn kiểm tra đoạn mã này, hãy để ý rằng có hai hành vi có thể khi người dùng nhấp vào một mục danh sách: phụ thuộc vào bố trí nào trong hai bố trí đang hiện hoạt, nó có thể hoặc tạo và hiển thị một phân đoạn mới để hiển thị chi tiết trong cùng hoạt động (thêm phân đoạn vào {@link android.widget.FrameLayout}), hoặc bắt đầu một hoạt động mới (tại đó phân đoạn có thể được hiển thị).

{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java titles}

Phân đoạn thứ hai, {@code DetailsFragment} sẽ hiển thị tóm tắt vở kịch cho mục được chọn từ danh sách trong {@code TitlesFragment}:

{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details}

Nhớ lại ở lớp {@code TitlesFragment} rằng, nếu người dùng nhấp vào một mục danh sách và bố trí hiện tại không có dạng xem {@code R.id.details} (là nơi mà {@code DetailsFragment} thuộc về), khi đó, ứng dụng sẽ bắt đầu hoạt động {@code DetailsActivity} để hiển thị nội dung của mục đó.

Sau đây là {@code DetailsActivity}, nó chỉ đơn thuần nhúng {@code DetailsFragment} để hiển thị tóm tắt vở kịch được chọn khi màn hình ở hướng đứng:

{@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentLayout.java details_activity}

Lưu ý rằng hoạt động này tự kết thúc nếu cấu hình là khổ ngang, sao cho hoạt động chính có thể chiếm lấy và hiển thị {@code DetailsFragment} bên cạnh {@code TitlesFragment}. Điều này có thể xảy ra nếu người dùng bắt đầu {@code DetailsActivity} ở dạng hướng đứng, nhưng sau đó xoay thành khổ ngang (làm vậy sẽ bắt đầu lại hoạt động hiện tại).

Để biết thêm mẫu sử dụng phân đoạn (và toàn bộ tệp nguồn cho ví dụ này), hãy xem ứng dụng mẫu API Demos có sẵn trong ApiDemos (có thể tải xuống từ Thành phần SDK Mẫu).