之前的博文我们简单讲了一下Fragment的管理方式以及对应方式下 Fragment 的生命周期是怎么样的,如果感兴趣的话可以移步
Fragment的简单使用 ,说的有不妥支出,烦请不吝赐教。
这篇博文我们来简单探讨一下 Fragment 的数据传递。
Fragment 的数据传递方式主要包括 Fragment 和 Activity 之前以及 Fragment 和 Fragment 之间。接下来我们就来一个一个来看下怎么传递。
Fragment 与 Activity 之前的数据传递
1、Activity 向 Fragment 传递数据
由于 Fragment 是依附于 Activity 的,所以Activity 向 Fragment 传递数据比较简单。
1)、通过创建 Fragment 的时候setArguments传递数据。这里我们先看下Android Studio 在新建 Fragment 的时候给我们建议的代码
public class BlankFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public BlankFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment BlankFragment.
*/
// TODO: Rename and change types and number of parameters
public static BlankFragment newInstance(String param1, String param2) {
BlankFragment fragment = new BlankFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank, container, false);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
这段代码写出了建议的 Activity 和 Fragment 之前传递数据的方式。我们首先来看 Activity创建Fragment的时候如何进行传递数据以及 Fragment 中如何接收 Activity传递过来的数据。
通过上面代码我们看到,在Activity 创建 Fragment 的时候可以可以通过setArguments来传递参数,然后在 Fragment 的 onCreate 中通过 getArguments 来获取传递过来的参数。
注意:newInstance 只是一个工厂类方法,你完全可以不用这个工厂方法,直接 new 一个 Fragment,然后再通过 setArguments 方式来传值。在这里要强调一点,不要通过重载构造方法的方式来传值,至于为什么我们以后的博文会继续介绍的,如果你等不及了也可以先自行查阅相关资料
2)、第一种方式是在实例化的时候进行传值的,那么当我们想在实例化过后想对应的 Fragment 传递数据怎么办呢?
a)、可以在 Activity 中保存一个 Fragment 的引用,然后就可以在 Activity 中通过调用 Fragment 的公共方法来进行传递数据。
b)、如果没有 Fragment 引用也没有关系,可以通过getSupportManager.findFragmentByTag 和 getSupportManager.findFragmentById来获取到 Fragment,然后再调用其公共方法来进行数据传递。
下面我们通过代码来看下这种方式是如何使用的:
我们先创建一个 Fragment
public class Com1Fragment extends Fragment {
private TextView mTvData;
private String data;
public Com1Fragment() {
// Required empty public constructor
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle arguments = getArguments();
if (arguments != null) {
data = arguments.getString("DATA", "");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.fragment_com1, container, false);
mTvData = contentView.findViewById(R.id.tv_data);
mTvData.setText(data);
return contentView;
}
public void changeData(String data) {
if (data != null && mTvData != null) {
this.data = data;
mTvData.setText(data);
}
}
}
然后再创建一个Activity 来放置这个 Fragment,然后在这个 Activity 中放置几个按钮用来展示不同的传值方式。
public class Com1Activity extends AppCompatActivity {
Com1Fragment fragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_com1);
findViewById(R.id.btn_add_fragment_with_data).setOnClickListener(view->{
addFragment();
});
findViewById(R.id.btn_data_with_reference).setOnClickListener(view -> {
sendDataWithReference();
});
findViewById(R.id.btn_data_with_tag).setOnClickListener(view->{
sendDataWidthTag();
});
}
private void addFragment() {
if (fragment == null) {
fragment = new Com1Fragment();
Bundle args = new Bundle();
args.putString("DATA", "data from initialization");
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction().add(R.id.fl_container, fragment, "Com1Fragment").commit();
}
}
private void sendDataWithReference() {
if (fragment != null && fragment.isAdded()) {
fragment.changeData("data from reference");
}
}
private void sendDataWidthTag() {
Fragment fragmentByTag = getSupportFragmentManager().findFragmentByTag("Com1Fragment");
if (fragmentByTag instanceof Com1Fragment) {
((Com1Fragment) fragmentByTag).changeData("data from tag");
}
}
}
下面是展示效果
以上就是Activity 向 Fragment 的传值方式。
2、Fragment 向 Activity 传值
1)、通过 Fragment 的 getActivity 方法获取到 Activity 实例,然后调用 Activity的公共方法。
我们在刚才的代码的基础上进行修改。在 Activity 中增加一个 TextView接受 Fragment 传递过来的数据。下面是部分代码:
Activity 中加个public 方法
public void receiveDataFromReference(String data) {
TextView tv_data = findViewById(R.id.tv_receive_data_from_reference);
tv_data.setText(data);
}
Fragment 中加个方法向 Activity 发送数据
private void sendDataToActivity() {
FragmentActivity activity = getActivity();
if (activity instanceof Com1Activity) {
((Com1Activity) activity).receiveDataFromReference("data from fragment by reference");
}
}
下面我们看下效果
2)、通过接口传递
第一种方式看起来比较简单,代码量也少,但是 Fragment 与 Activity 的耦合性太高(Fragment 必须知道Activity 开放了哪些方法供 Fragment 调用),不符合搞内聚、低耦合的原则。之前我们看到了谷歌在为我们自动创建的 Fragment 代码中可以看到其建议的 Fragment 与 Activity 的传递数据的方式,那就是通过接口的方式。下面我们来看下具体的效果,代码可以看上面的谷歌建议的写法,我就不贴了。
Fragment 与 Fragment 之间的数据传递
在我自己考虑这个问题之前我也看过网上很多人写的关于 Fragment 与 Fragment 之间的数据传递方式,比如说用getActivity().getSupportFragmentManager().findFragmentByTag(tag)。但是我本人觉得 Fragment 之间的数据传递还是应该归为 Fragment 和 Activity 以及 Activity 和 Fragment 之间的数据传递。也就是说通过 Activity 这层(类似于 中转一样)进行数据传递。比如说我现在有两个 Fragment1和 Fragment2都依附于 Activity,如果Fragment1想向 Fragment2传递数据怎么办呢?我的想法是Fragment1先把数据传递到 Activity,然后通过 Activity中转一下,把数据传递到 Fragment2中。这样虽然看起来麻烦一些,但是这样可以是的 Fragment1、Fragment2以及 Activity 之间耦合度都大大降低了。
好了,Fragment 的数据传递相关内容就写到这了,如果有遗漏或者不对的地方,请各位大神指正。