本文详细介绍fragment的几种通信的方式
Activty向fragment中传递数据
只需要在对应的触发事件中写如下代码即可:
public void ck(View view) {
// 获取fragment管理器
FragmentManager fm = getFragmentManager();
// 使用事物,为了保证数据的一致性和完整性
FragmentTransaction ft = fm.beginTransaction();
// 将需要添加的fragment创建出来
LeftFragment left = new LeftFragment();
// 创建一个数据包
Bundle b=new Bundle();
// 构造需要传递的数据,并且传递出去
b.putInt("id",R.mipmap.delaiwen);
left.setArguments(b);
// 使用replace方式添加fragment
ft.add(R.id.fragment_contont,left);
ft.addToBackStack(null);
// 提交事物
ft.commit();
}
可以通过使用Bundle数据包,向fragment传递数据,当然对应的fragment也需要做相应的操作,我这里是将传过来的图片显示到image上面:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.left_fragme_layout, container, false);
ImageView lv= (ImageView) view.findViewById(R.id.iamge_default);
lv.setImageResource(getArguments().getInt("id"));
return view;
}
一般情况下,我们会在createview方法中取出数据,这样可以显示到UI上,不能通过有参构造的方法进行设置值,因为当屏幕旋转的时候,activity会进行销毁,对应的fragment也会进行销毁,然后重建,在重建的过程中,会调用fragment的无参构造方法(这也就是为什么fragment必须要有一个空参构造的原因)系统在创建fragment对象的时候,会看有没有被设置arguments,若有的话,会帮我们设置上,这样也可以防止数据丢失
Activity操作fragment中的数据
可以在Activity通过:
FragmentManager fm=getFragmentManager();
LeftFragment left= (LeftFragment) fm.findFragmentByTag("left");
来获取声明了Tag的fragment,然后进行相应的操作,若是想对fragment中的UI进行操作,则直接可以通过以下代码来实现:
ImageView images= (ImageView) findViewById(R.id.iamge_default);
images.setImageResource(R.mipmap.jinkesi);
这里直接在activity中通过findviewById来找到对应的组件,直接对其进行操作,(
注意:必须等fragment完成了oncreateView方法之后,也就是等fragment呈现出来之后再调用 此方法,否则会出现空指针异样的问题)
下面是效果图:
Fragment向Activty中传值
fragment可以通过getActivity方法获取和它绑定的activity,不过此方法应该在onAttach之后获取,因为fragment是在onAttach方法中和activty建立关系的。若想操作activity中的UI组件或者传递值可以使用以下代码:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.left_fragme_layout, container, false);
ImageView lv= (ImageView) view.findViewById(R.id.iamge_default);
lv.setImageResource(getArguments().getInt("id"));
btn= (Button) view.findViewById(R.id.change_color);
Log.i(TAG, "onCreateView: "+btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().findViewById(R.id.activity_main).setBackgroundColor(Color.YELLOW);
}
});
return view;
}
可以通过getActivity()获取activty对象,拿到了activty对象,就可以直接操作activity中的数据了,在这里演示的是进行改变activty的背景颜色,效果图如下:
上图中先是呈现出fragment,然后通过点击fragment中的按钮,改变activty的背景颜色
当然谷歌官方觉得这种方式会导致耦合性较高,推荐我们使用接口回调的方式来实现fragment和activity之间的数据交互
我们在fragment中定义一个内部接口:
public interface FragmentCallbacks{
void change(int color);
}
并且维护一个此接口的对象,在Onattach()方法中进行获取此对象(也可以在oncreateView中获取此对象,可以起到优化内存的效果,晚绑定,早结束)。
private FragmentCallbacks callbacks;
@Override
public void onAttach(Context context) {
super.onAttach(context);
callbacks= (FragmentCallbacks) getActivity();
}
在对应的事件中调用此接口的方法(
此原理是多态,虽然这里调用的是父类中的方法,但其实父类中的方法会被屏蔽掉,调用子类中具体实现的方法)
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
callbacks.change(Color.YELLOW);
}
});
其实是执行子类中的方法。
好了,fragment中的工作完成了,需要让activty实现此内部接口,并重写抽象方法:
public class MainActivity extends AppCompatActivity implements LeftFragment.FragmentCallbacks {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void change(int color) {
LinearLayout ll = (LinearLayout) findViewById(R.id.activity_main);
ll.setBackgroundColor(color);
}
这边是谷歌官方推荐的方法;
注意:这里的回调接口也是为了给activity传值,由于fragment可以获取到activity的对象,通过getActivity然后强转,我们可以直接调用activity中定义的方法来进行设置值,我们定义成接口回调是为了提高扩展性,fragment可以不依赖于宿主,若写死的话,需要每次都进行强转甚至需要判断,定义成接口,只需要子类实现此接口,然后进行强制类型转换即可;大大提高扩展性;