Fragment trong lập trình Android – phần 3 ( quản lý tác vụ )

(ZmikiSoft.com) – Fragment trong lập trình Android – phần 3 ( quản lý tác vụ ).

Fragment tạm dịch là phân đoạn.

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 FragmentManager. Để có nó, hãy gọi getFragmentManager() từ hoạt động của bạn.

Một số việc bạn có thể làm với FragmentManager bao gồm:

  • Nhận các phân đoạn tồn tại trong hoạt động, bằng findFragmentById() (đối với các phân đoạn cung cấp UI trong bố trí hoạt động) hoặc findFragmentByTag() (đối với các phân đoạn có hoặc không cung cấp UI).
  • Lấy phân đoạn ra khỏi ngăn xếp, bằng popBackStack() (mô phỏng một câu lệnh Quay lại của người dùng).
  • Đăng ký một đối tượng theo dõi cho những thay đổi đối với ngăn xếp, bằng addOnBackStackChangedListener().

Để 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 FragmentManager.

Như minh họa trong phần trước, bạn cũng có thể sử dụng FragmentManager để mở một 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 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 FragmentTransaction từ FragmentManager như sau:

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = 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ư add(), remove(), và replace(). Sau đó, để áp dụng giao tác cho hoạt động, bạn phải gọi commit().

Trước khi bạn gọi commit(), tuy nhiên, bạn có thể muốn gọi 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, 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 R.id.fragment_container. Bằng cách gọi 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 add() khác hoặc remove()) và gọi addToBackStack(), khi đó, tất cả thay đổi được áp dụng trước khi bạn gọi 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 FragmentTransaction không quan trọng, ngoại trừ:

  • Bạn phải gọi commit() cuối cùng
  • Nếu bạn thêm nhiều phân đoạn vào cùng bộ chứa, khi đó thứ tự mà bạn thêm chúng sẽ xác định thứ tự chúng xuất hiện trong phân cấp dạng xem

Nếu bạn không gọi 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 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 setTransition() trước khi thực thi.

Việc gọi 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 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 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 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 commitAllowingStateLoss().

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


Mặc dù Fragment được triển khai như một đối tượng độc lập với 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ể Activity bằng 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 = getActivity().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 Fragment từ FragmentManager, bằng cách sử dụng findFragmentById() hoặc 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 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 OnArticleSelectedListener và khống chế 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 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 OnArticleSelectedListener bằng cách đổi kiểu Activity mà được chuyển vào 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 ClassCastException. Nếu thành công, thành viên mListener giữ một tham chiếu tới triển khai OnArticleSelectedListenercủ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 OnArticleSelectedListener. Ví dụ, nếu phân đoạn A là một phần mở rộng của 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 onListItemClick() trong phân đoạn, và nó lại gọi 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.withAppendedId(ArticleColumns.CONTENT_URI, id);
        // Send the event and Uri to the host activity
        mListener.onArticleSelected(noteUri);
    }
    ...
}

Tham số id được chuyển vào 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ừ 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 khaionCreateOptionsMenu(). Tuy nhiên, để phương pháp này nhận lệnh gọi, bạn phải gọi setHasOptionsMenu() trong khi 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 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 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 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 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 onContextItemSelected().

Khóa học lập trình Android
Khóa học lập trình Java
Khóa học lập trình iOS
Khóa học lập trình Objective-C/Swift