Truyền dữ liệu giữa 2 fragment

Cách truyền dữ liệu giữa hai fragment

Fragment trong android là gì?

Với những ứng dụng phức tạp cần nhiều layout khác nhau trên cùng một màn hình (activity) và những layout đó còn được sử dụng ở các màn hình khác. Hơn thế nữa với các màn hình với kích thước lớn (tablet...) người dùng thường có xu hướng dùng cả hai tay để thao tác, nhưng với giao diện truyền thống một tablet không khác gì một thiết bị di động . Vì vậy, không những gây lãng phí không gian mà còn gây khó khăn, bất tiện cho người dùng khi thao tác. Chính vì lý do đó mà fragment ra đời. Fragment được xem như một sub-activity. Fragment cũng có layout riêng của nó, cũng có các hành vi và vòng đời riêng. Vậy là chúng ta đã đi lướt qua khái niệm fragment và nguyên nhân cần có nó rồi. Nhưng trong một số trường hợp giữa các fragment cần có sự trao đổi thông tin thì việc truyền dữ liệu giữa chúng là điều hết sức cần thiết.

Hướng dẫn cách truyền dữ liệu giữa hai fragment

Có nhiều cách để truyền dữ liệu qua lại giữa hai đối tượng fragment, trong đây mình sẽ giới thiệu cách đơn giản mình vẫn hay sử dụng nhất: FragmentA -> Activity -> FragmentB. Có nhiều bạn sẽ thắc mắc tại sao lại không truyền trực tiếp từ fragmentA -> fragmentB mà lại truyền lòng vòng như thế? Bởi vì đối với fragment bạn không chắc nó luôn luôn được khởi tạo. Vì vậy để chắc chắn fragmentB đã được khởi tạo thì chúng ta phải thông qua activity. Tránh giao tiếp trực tiếp giữa hai fragment.

Bước 1: Khởi tạo project và tạo layout

Mô tả tí nha: Ứng dụng có 2 fragment, fragment trên sẽ có 2 EditText để nhập tên và tuổi, fragment bên dưới gồm 2 TextView để hiển thị dữ liệu. Sau khi nhập và bấm button SEND thì kết quả sẽ được gởi và hiển thị ở fragment bên dưới.

Bước 2: Tạo interface DemoFragmentInterface.java

Có thể khai báo interface ở một file riêng hoặc khai báo bên trong fragment.

public interface DemoFragmentInterface {
        void sendData(String name, String age);
    }

Bước 3: Tạo Activity MainActivity.java và implement interface vừa tạo

  • Về phía layout của activity, trong file xml khai báo 2 FrameLayout và thực hiện nhúng fragment vào activity bằng code.
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        DemoFragment demoFragment = new DemoFragment();
        transaction.add(R.id.containerTop, demoFragment);

        Demo1Fragment demo1Fragment = new Demo1Fragment();
        transaction.add(R.id.containerBottom, demo1Fragment);

        transaction.commit();
    }
  • Ta tiến hành implements interface vừa tạo
public class MainActivity extends AppCompatActivity implements DemoFragmentInterface {...}
  • Tới đây chắc hẳn nó sẽ báo lỗi phải không nào. Vì mình chưa định nghĩa lại hàm abstract của interface mà. Hãy tiến hành định nghĩa lại hàm sendData(), Tiếp theo ta cần get đối tượng fragment cần hiển thị thông tin, kiểm tra nó đã được khởi tạo hay chưa và gọi tới phương thức hiển thị thông tin của nó. Lưu ý: phương thức showInfor() ta sẽ định nghĩa trong Fragment hiển thị.
    @Override
    public void sendData(String name, String age) {
        Demo1Fragment demo1Fragment = (Demo1Fragment) getSupportFragmentManager().findFragmentById(R.id.containerBottom);

        if (demo1Fragment != null || demo1Fragment.isInLayout()) { // kiem tra fragment can truyen data den co thuc su ton tai va dang hien
            demo1Fragment.showInfor(name, age);
        } else {
            Toast.makeText(getApplicationContext(), "Fragment is not exist", Toast.LENGTH_LONG).show();
        }
    }

Bước 4: Tạo fragment DemoFragment gởi dữ liệu

  • Khai báo một biến interface dùng để lắng nghe thay đổi từ Fragment (Khi người dùng nhập đầy đủ và click button send), nhưng ta vẫn chưa xong đâu nhé! Đó chỉ mới là khai báo, việc tiếp theo là gán nó với Activity để Activity biết có thay đổi từ Fragment.
private DemoFragmentInterface listener;
  • Override lại hàm onAttach để kiểm tra xem cái Activity hiện tại đã implement cái interface kia chưa. Tại đây ta tiến hành gán sự kiện cho biến interface đó.
   @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof MainActivity)
            this.listener = (DemoFragmentInterface) context; // gan listener vao MainActivity 
        else
            throw new RuntimeException(context.toString() + " must implement onViewSelected!");
    }
  • Chúng ta xử lý và kiểm tra dữ liệu nêu mọi thứ ổn thì ta tiến hành gọi hàm sendData()
String name = edtName.getText().toString().trim();
String age = edtAge.getText().toString().trim();
if (!name.equals("") && !age.equals("")) {
       listener.sendData(name, age);
} else if (name.equals("")) {
       edtName.requestFocus();
} else {
       edtAge.requestFocus();
}
  • Toàn bộ code phần Fragment gởi thông tin
public class DemoFragment extends Fragment implements View.OnClickListener {

    private EditText edtName, edtAge;
    private Button btnSend;
    private DemoFragmentInterface listener; // tao mot the hien cua interface vua tao
    
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof MainActivity)
            this.listener = (DemoFragmentInterface) context; // gan listener vao MainActivity 
        else
            throw new RuntimeException(context.toString() + " must implement onViewSelected!");
        Toast.makeText(getActivity(), "Fragment : onAttach", Toast.LENGTH_LONG).show();
    }
                    edtName.requestFocus();

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Toast.makeText(getActivity(), "Fragment : onCreateView", Toast.LENGTH_LONG).show();
        View view = inflater.inflate(R.layout.fragment_demo1, container, false);
        addControllers(view);
        addEvents();

        return view;
    }

    private void addEvents() {
        btnSend.setOnClickListener(this);
    }

    private void addControllers(View view) {
        edtName = (EditText) view.findViewById(R.id.edName);
        edtAge = (EditText) view.findViewById(R.id.edAge);
        btnSend = (Button) view.findViewById(R.id.btnSend);
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.btnSend:
                String name = edtName.getText().toString().trim();
                String age = edtAge.getText().toString().trim();

                if (!name.equals("") && !age.equals("")) {
                    listener.sendData(name, age);
                } else if (name.equals("")) {
                    edtName.requestFocus();
                } else {
                    edtAge.requestFocus();
                }
                break;
        }
    }

}

Bước 5: Set nội dung cho Demo1Fragment

  • Ở fragment này chúng ta chỉ cần khai báo phương thức showInfor() hiển thị dữ liệu cho nó.
public class Demo1Fragment extends Fragment {

    private TextView tvName, tvAge;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_demo2, container, false);
        addControllers(view);

        Toast.makeText(getActivity(), "Fragment Bottom: onCreateView", Toast.LENGTH_LONG).show();

        return view;
    }

    private void addControllers(View view) {
        tvName = (TextView) view.findViewById(R.id.tvName);
        tvAge = (TextView) view.findViewById(R.id.tvAge);
    }
    // set text cho TextView 
    public void showInfor(String name, String age) {
        tvName.setText(name);
        tvAge.setText(age);
    }
}

Vậy là xong rồi, cùng xem thành quả nào!

Kết luận

Vậy là chúng ta đã hoàn thành một cách truyền dữ liệu đơn giản giữa hai fragment rồi. Ngoài cách trên các bạn còn có thể tìm kiếm thêm một số cách khác để phù hợp hơn với tình huống mình gặp phải, không nhất thiết phải làm giống hoàn toàn như trên nhé. Cảm ơn các bạn đã theo dõi. Đừng quên để lại bình luận bên dưới những lỗi mình đã mắc phải để bài viết được tốt hơn nhé!