Giao dịch mảnh

Trong thời gian chạy, FragmentManager có thể thêm, xoá, thay thế và thực hiện các thao tác khác với các mảnh (fragment) để phản hồi khi người dùng tương tác. Mỗi tập hợp thay đổi mảnh mà bạn xác nhận (commit) được gọi là một giao dịch (transaction) và bạn có thể chỉ định việc cần làm bên trong giao dịch bằng cách sử dụng các API mà lớp FragmentTransaction cung cấp. Bạn có thể nhóm nhiều hành động (action) thành một giao dịch duy nhất, ví dụ: một giao dịch có thể thêm hoặc thay thế nhiều mảnh. Thao tác nhóm này có thể hữu ích khi bạn hiển thị nhiều mảnh đồng cấp trên cùng một màn hình, chẳng hạn như với chế độ xem phân tách.

Bạn có thể lưu từng giao dịch vào ngăn xếp lui do FragmentManager quản lý, cho phép người dùng di chuyển trở lại thông qua các thay đổi mảnh – tương tự như việc di chuyển ngược qua các hoạt động.

Bạn có thể nhận bản sao của FragmentTransaction từ FragmentManager bằng cách gọi beginTransaction(), như trong ví dụ sau:

Kotlin

val fragmentManager = ...
val fragmentTransaction = fragmentManager.beginTransaction()

Java

FragmentManager fragmentManager = ...
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

Lệnh gọi cuối cùng trên mỗi FragmentTransaction phải xác nhận giao dịch. Lệnh gọi commit() báo hiệu cho FragmentManager rằng tất cả thao tác (operation) đã được thêm vào giao dịch.

Kotlin

val fragmentManager = ...
// The fragment-ktx module provides a commit block that automatically
// calls beginTransaction and commit for you.
fragmentManager.commit {
    // Add operations here
}

Java

FragmentManager fragmentManager = ...
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

// Add operations here

fragmentTransaction.commit();

Cho phép sắp xếp lại các thay đổi về trạng thái mảnh

Mỗi FragmentTransaction sẽ sử dụng setReorderingAllowed(true):

Kotlin

supportFragmentManager.commit {
    ...
    setReorderingAllowed(true)
}

Java

FragmentManager fragmentManager = ...
fragmentManager.beginTransaction()
    ...
    .setReorderingAllowed(true)
    .commit();

Để tương thích với hành vi, cờ sắp xếp lại không được bật theo mặc định. Tuy nhiên, bạn cần phải cho phép FragmentManager thực thi FragmentTransaction đúng cách, đặc biệt là khi ứng dụng này hoạt động trên ngăn xếp lui cũng như chạy ảnh động và hiệu ứng chuyển đổi. Việc bật cờ sẽ đảm bảo rằng nếu nhiều giao dịch được thực hiện cùng nhau, thì mọi mảnh trung gian (tức là các giao dịch được thêm vào và thay thế ngay lập tức) sẽ không trải qua các thay đổi trong vòng đời hoặc ảnh động/hiệu ứng chuyển tiếp sẽ được thực thi. Lưu ý rằng cờ này ảnh hưởng đến cả quá trình thực hiện giao dịch ban đầu lẫn việc đảo ngược giao dịch bằng popBackStack().

Thêm và xoá mảnh

Để thêm một mảnh vào FragmentManager, hãy gọi add() trên giao dịch. Phương thức này sẽ nhận được mã nhận dạng của vùng chứa (container) cho mảnh, cũng như tên lớp của mảnh bạn muốn thêm. Mảnh đã thêm sẽ được chuyển sang trạng thái RESUMED. Chúng tôi rất khuyến khích việc vùng chứa là một FragmentContainerView – một phần của hệ phân cấp thành phần hiển thị.

Để xoá một mảnh khỏi máy chủ lưu trữ, hãy gọi remove(), truyền vào thực thể mảnh được truy xuất từ trình quản lý mảnh thông qua findFragmentById() hoặc findFragmentByTag(). Nếu thành phần hiển thị của mảnh trước đây đã được thêm vào vùng chứa, thì thành phần hiển thị đó sẽ bị xoá khỏi vùng chứa tại thời điểm này. Mảnh bị xoá sẽ được chuyển sang trạng thái DESTROYED.

Hãy sử dụng replace() để thay thế một mảnh hiện có trong vùng chứa bằng một thực thể của lớp mảnh mới mà bạn cung cấp. Việc gọi replace() tương đương với việc gọi remove() bằng một mảnh trong vùng chứa và thêm một mảnh mới vào chính vùng chứa đó.

Đoạn mã sau đây cho biết cách bạn có thể thay thế một mảnh bằng một mảnh khác:

Kotlin

// Create new fragment
val fragmentManager = // ...

// Create and commit a new transaction
fragmentManager.commit {
    setReorderingAllowed(true)
    // Replace whatever is in the fragment_container view with this fragment
    replace<ExampleFragment>(R.id.fragment_container)
}

Java

// Create new fragment and transaction
FragmentManager fragmentManager = ...
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setReorderingAllowed(true);

// Replace whatever is in the fragment_container view with this fragment
transaction.replace(R.id.fragment_container, ExampleFragment.class, null);

// Commit the transaction
transaction.commit();

Trong ví dụ này, một bản sao mới của ExampleFragment thay thế mảnh (nếu có) hiện có trong vùng chứa bố cục được xác định bởi R.id.fragment_container.

Theo mặc định, các thay đổi đã thực hiện trong FragmentTransaction sẽ không được thêm vào ngăn xếp lui. Để lưu các thay đổi đó, bạn có thể gọi addToBackStack() trên FragmentTransaction. Để biết thêm thông tin, hãy xem Trình quản lý mảnh.

Xác nhận (commit) không đồng bộ

Việc gọi commit() sẽ không thực hiện giao dịch ngay lập tức. Thay vào đó, giao dịch được lên lịch để chạy trên chuỗi giao diện người dùng chính ngay khi có thể thực hiện. Tuy nhiên, nếu cần, bạn có thể gọi commitNow() để chạy giao dịch mảnh trên luồng giao diện người dùng (UI thread) ngay lập tức.

Xin lưu ý rằng commitNow không tương thích với addToBackStack. Ngoài ra, bạn có thể thực thi tất cả FragmentTransactions đang chờ xử lý do các lệnh gọi commit() chưa chạy gửi bằng cách gọi executePendingTransactions(). Phương pháp này tương thích với addToBackStack.

Đối với phần lớn trường hợp sử dụng, bạn chỉ cần duy nhất commit().

Thứ tự hoạt động rất quan trọng

Thứ tự bạn thực hiện các thao tác trong FragmentTransaction là rất quan trọng, đặc biệt là khi sử dụng setCustomAnimations(). Phương thức này áp dụng ảnh động nhất định cho tất cả thao tác mảnh theo sau.

Kotlin

supportFragmentManager.commit {
    setCustomAnimations(enter1, exit1, popEnter1, popExit1)
    add<ExampleFragment>(R.id.container) // gets the first animations
    setCustomAnimations(enter2, exit2, popEnter2, popExit2)
    add<ExampleFragment>(R.id.container) // gets the second animations
}

Java

getSupportFragmentManager().beginTransaction()
        .setCustomAnimations(enter1, exit1, popEnter1, popExit1)
        .add(R.id.container, ExampleFragment.class, null) // gets the first animations
        .setCustomAnimations(enter2, exit2, popEnter2, popExit2)
        .add(R.id.container, ExampleFragment.class, null) // gets the second animations
        .commit()

Giới hạn vòng đời của mảnh

FragmentTransactions có thể ảnh hưởng đến trạng thái vòng đời của các mảnh riêng lẻ được thêm trong phạm vi giao dịch. Khi tạo FragmentTransaction, setMaxLifecycle() sẽ đặt trạng thái tối đa cho mảnh đã cho. Ví dụ: ViewPager2 sử dụng setMaxLifecycle() để giới hạn các mảnh ngoài màn hình ở trạng thái STARTED.

Hiện và ẩn thành phần hiển thị của mảnh

Sử dụng các phương thức FragmentTransaction, show()hide() để hiện và ẩn thành phần hiển thị của các mảnh đã được thêm vào vùng chứa. Các phương thức này thiết lập chế độ hiển thị của các thành phần hiển thị của mảnh mà không ảnh hưởng đến vòng đời của mảnh.

Mặc dù bạn không cần phải sử dụng giao dịch mảnh để chuyển đổi chế độ hiển thị của các thành phần hiển thị trong một mảnh, nhưng các phương pháp này hữu ích đối với trường hợp bạn muốn thay đổi trạng thái hiển thị liên kết với các giao dịch trong ngăn xếp lui.

Đính kèm và tách rời mảnh

Phương thức FragmentTransaction detach() sẽ tách rời mảnh khỏi giao diện người dùng và huỷ bỏ thứ bậc của hệ phân cấp thành phần hiển thị. Mảnh này còn nguyên trạng thái (STOPPED) như khi được đặt vào ngăn xếp lui. Tức là mảnh đã bị xoá khỏi giao diện người dùng nhưng vẫn do trình quản lý mảnh quản lý.

Phương thức attach() sẽ đính kèm lại một đoạn trước đó từng bị tách rời ra. Điều này khiến hệ phân cấp thành phần hiển thị được tạo lại, đính kèm với giao diện người dùng và hiển thị.

FragmentTransaction được coi là một tập hợp các thao tác atom đơn, nên các lệnh gọi đến detachattach trên cùng một thực thể mảnh trong cùng một giao dịch sẽ huỷ liên kết với nhau một cách triệt để, do đó, tránh việc phá huỷ và tái tạo ngay lập tức trên giao diện người dùng của mảnh. Hãy sử dụng các giao dịch riêng biệt, phân tách nhau bằng executePendingOperations() khi sử dụng commit(), nếu bạn muốn tách rời rồi sau đó đính kèm lại một mảnh.