Fragment的数据传递

之前的博文我们简单讲了一下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 的数据传递相关内容就写到这了,如果有遗漏或者不对的地方,请各位大神指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值