上一篇讲了Fragment的一些基本用法和生命周期,这一篇简单过一下Fragment的通信,包括Activity向Fragment传参,Fragment和Activity之间相互通信,以及Fragment之间的相互通信。
用这么一个示例来展示全部五部分的内容。App启动后先是只有左边三分之一的布局(这是直接定义在Activity的布局文件中的),点击“加在Fragment并向其传参”按钮,会把中间和右边剩下三分之二的布局(位于两个Fragment中)加载上来,加载的同时传递左边布局文本框中填写的字符串。点击左边布局中的“获取Fragment1中填写的值”按钮可以拿到中间布局文本框的值,类似的点击中间布局中的“获取Activity中填写的值”按钮可以拿到左边布局文本框中的值。最后点击中间或右边布局中的“获取FragmentX中填写的值”,会分别用两种方法去取得右边或中间布局文本框中的值。
一、向Fragment时传参
注意到Fragment类中的setArguments()和getArguments()方法了吗?将要传递的参数放进Bundle中,即可实现启动Fragment时传参,就像这样。
Bundle bundle = new Bundle();
bundle.putString("param", editText.getText().toString());
fragment1.setArguments(bundle);
getArguments().getString("param");
第一段代码是传递参数,第二段代码是取出参数,当然并不一定要在Fragment被创建后立即取出参数——直到销毁前,任何地方都是可以的,不过传递参数就有要求了,一般放在Fragment构造之后。
二、Activity获取Fragment中的值
要拿到Fragment中某个EditText中填写的内容,自然要先拿到Fragment本身,然后拿到Fragment绑定的View,接着才能像以前那样,用findViewById找到其中的EditText并进行进一步操作。要拿到Fragment绑定的View,观察发现Fragment类中有一个getView()方法返回的就是这个Fragment的根布局(其实就是onCreateView()方法返回的那个咯)。而要拿到Fragment本身,回想之前我们在动态更改Fragment时用过一个叫做FragmentManager的东西,所有与当前Activity关联的Fragment都归它管理,自然就可以从它这拿到已经添加的Fragment,方法又有两种,一是findFragmentById()方法,二是findFragmentByTag()方法,两者的区别就在于一个是通过android:id去寻找,另一个则是通过在添加Fragment时设置的TAG去查找。这里以通过TAG查找为例。
View view = getFragmentManager().findFragmentByTag("fragment1").getView();
EditText editText = (EditText) view.findViewById(R.id.editText);
editText.getText().toString().trim();
三、Fragment获取Activity中的值
同样是在前一篇中用过Fragment的一个方法——getActivity(),当时是用在一个需要传入Context的地方,因为Activity本身就继承自Context。现在,类比刚刚Activity获取Fragment中的值时需要先拿到Fragment,反过来Fragment获取Activity中的值自然就要先获取到Activity,然后又是findViewById……
EditText editText = (EditText) getActivity().findViewById(R.id.editText);
editText.getText().toString();
四、Fragment间相互通信
前三节阐述的都是Activity和Fragment之间的通信,这一节则是关于Fragment间的通信。方法有两种,第一种和前面的很相似,就是想办法拿到要通信的另一个Fragment,然后不就和Activity获取Fragment中的值一样了吗?不要想说因为Fragment是归Activity用FragmentManager管理的,其实在Fragment中同样有getFragmentManager()方法(观察的更仔细的话会发现,其实这里返回的FragmentManager和与它关联的Activity返回的是同一个),我们就可以用这样的办法拿到另一个Fragment,代码实现和第二节几乎是一模一样的。
不过,Google在其教程中推荐另一种方法——回调接口,具体的做法和一般Java开发时定义回调是一样的,但这里的例子和官方教程略有不同。
定义接口(Fragment1类中)
public void setCallback(Callback callback) {
EditText editText = (EditText) getView().findViewById(R.id.editText);
callback.getValue(editText.getText().toString());
}
public interface Callback {
public void getValue(String value);
}
实现接口(Fragment2类中)
fragment1.setCallback(new Fragment1.Callback() {
@Override
public void getValue(String value) {
TextView textView1 = (TextView) view.findViewById(R.id.textView1);
textView1.append(value);
}
});