Sự khác nhau giữa addFragment và replaceFragment trong Android

Fragment trong Android

Khi làm việc với ứng dụng android chắc các bạn không thể không biết đến Fragment.

Fragment là một phần giao diện người dùng hoặc hành vi của một ứng dụng. Fragment có thể được đặt trong Activity hoặc chính trong Fragment, nó có thể cho phép thiết kế Activity, Fragment với nhiều mô-đun. Có thể nói Fragment là một loại sub-Activity. Fragment cũng có layout của riêng của nó, cũng có các hành vi và vòng đời riêng.

Để khởi tạo 1 Fragment thường có 2 cách sau:

  1. Tạo 1 fragment từ file xml.
<fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.lap.demofragment.DemoFragment"/>
  1. Tạo 1 GroupView (thường là FrameLayout) rồi thêm Fragment từ code java.
<FrameLayout
    android:id="@+id/frame_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.frame_main, DemoFragment.newInstance());
// or 
// transaction.replace(R.id.frame_main, DemoFragment.newInstance());

cả 2 cách trên đều dùng để thêm 1 Fragment vào Activity (Fragment). Nhưng tôi dám chắc các Dev lập trình Android thường dùng cách 2 vì nó tiện lợi và có thể tùy biến thêm (add) hay gỡ bỏ (remove) 1 Fragment ra khỏi 1 View.

Như ở cách 2 mình nêu ở trên thì có 2 cách để bạn thêm 1 Fragment vào 1 View được định nghĩa trước trong file .xml. Về cơ bản thì cả 2 kiểu đều chung 1 mục đích nhưng mà xét về vòng đời của Fragment thì chúng có những điểm khác nhau khá cơ bản. Và dưới đây mình sẽ chỉ dẫn những điểm cơ bản về sự khác nhau giữa add() và replace().

Sự khác nhau giữa add() và replace() trong Fragment

  • add(): là thêm 1 fragment vào 1 View được khai báo trước trong file xml
  • replace(): là thay thế 1 fragment cũ bằng 1 fragment mới vào View được khai báo trước trong file xml. Nếu trong View chưa chứa fragment nào thì nó sẽ thêm mới fragment vào View.

1. Add() Khi bạn hiển 1 fragment bằng hàm add() "transaction.add()" thì là bạn đang thêm 1 fragment mới vào View và fragment cũ vẫn còn trong View. Thao tác này thực chất là bạn đang phủ (đè) 1 View với mới lên trên View cũ.

FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.add(R.id.frame_main, DemoFragment2.newInstance());
transaction.addToBackStack(null);
transaction.commit();

Và khi thực hiện gọi hàm add() thì fragment cũ sẽ không gọi vào hàm onPause() mà các tiến trình của nó vẫn chạy bình thường, chỉ đơn giản là View của nó được che đi bởi 1 View mới mà thôi. Như vậy khi bạn ấn nút "Back" cứng trên bàn phím hay là gọi sự kiện popBackStack() để remove fragment hiện tại thì fragment cũ sẽ không được khởi tạo lại (các hàm onResume(), onCreate(), onCreateView() không được gọi vì thực chất nó chưa bị kill hay là lưu vào trạng thái nghỉ) mà vẫn tiếp chạy những tiến trình còn đang dang dở.

Làm như vậy thì bộ nhớ RAM của bạn sẽ bị đầy lên vì khi bạn nhìn thấy 1 View mới mà View cũ (dữ liệu cũ nằm trên Fragment) không được lưu vào trạng thái nghỉ mà nó vẫn chiếm dụng dung lượng của RAM và CPU để chạy các tiến trình của mình.

2. Replace() Khi bạn hiển 1 fragment bằng hàm replace() "transaction.replace()" thì tức là bạn đã remove fragment cũ ra khỏi View và thay thế nó bằng 1 fragment mới hoàn toàn.

FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_main, DemoFragment2.newInstance());
transaction.addToBackStack(null);
transaction.commit();

Như vậy khi bạn gọi hàm replace() thì frament cũ sẽ gọi vào hàm onPause() và savedInstanceState lại trạng thái hiện tại của nó. Khi bạn gọi sự kiện popBackStack() ở fragment hiện tại để trở về fragment cũ thì fragment sẽ được khởi tạo lại với trạng thái được lưu trong savedInstanceState.

Vậy khi nào bạn nên sử dụng add() khi nào nên sử dụng replace().

  • Bạn nên sử dụng add() khi bạn vẫn muốn fragment hiện tại tiếp tục chạy. VD như fragment hiện tại của bạn đang thực hiện 1 tiến trình download hay đang chạy thực thi 1 tác vụ ngầm nào đó trong khi đó bạn vẫn muốn hiển thị 1 fragment mới để thực hiện các công việc khác và khi thực hiện xong bạn trở lại và muốn nhận kết quả ở fragment cũ.
  • Còn khi bạn thực hiện 1 thao tác hoàn toàn mới và độc lập hoàn toàn với fragment cũ thì bạn nên sử dụng replace() để tiết kiệm bộ nhớ cho ứng dụng, ngoài ra khi sử dụng replace() khi back trở về fragment trước thì hàm onResume() sẽ được gọi, tại đây bạn có thể refresh lại dữ liệu hiển thị trên View.

Trong Source demo mình có viết 2 hàm demo gọi 2 sự kiện add() và replace() fragment.

Khi bạn click nút Start sẽ thực hiện chạy 1 biến đếm và hiển thị lên màn hình. Khi bạn click vào add hay replace và back trở lại fragment cũ bạn sẽ thấy sự khác nhau cơ bản của 2 hàm này. link git : https://github.com/huyquyet/demoFragment