Fragment依赖于Activity,那么它们之间的通信就必须要涉及。通过自己的寻找和实践,知道了Fragment和Activity之间的通信方案大概有5种,各有优缺点,用哪个方案看需求吧。
上代码,开始分析。自己写了个小Demo:Fragment通信Demo ,里边有上边前4种通信方式。
demo中1、2、3为activity->fragment,2、3若要fragment->activiy则相关代码调换位置即可。4包含双向通信。
此方式还挺简单的,貌似是谷歌官方推荐的一种数据传递方式,如果遇到内存重启,系统会自动保存数据,和Activity中的Intent一个原理。
用Android Studio新建一个Fragment时,会自带一个函数:
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
/**
* 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 Fragment1.
*/
// TODO: Rename and change types and number of parameters
public static Fragment1 newInstance(String param1, String param2) {
Fragment1 fragment = new Fragment1();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
//保存数据
fragment.setArguments(args);
return fragment;
}
在Activity中新建Fragment实例的时候,直接传入想要传送的数据。
//1.直接传入参数 setArguments() 传递数据
Fragment1 fragment1 = Fragment1.newInstance(number1, number2);
取出数据在Fragment的OnCreat()中,用getArguments()函数取出。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//获取activity传递的数据
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
比如Activity向Fragment传递数据,首先,保证进行通信的Activity和Fragment使用同一个Handler实例对象。Activity中设置全局 变量hander,并给出其Setter方法。在响应事件中,封装数据到message中,然后进行发送。
//2.使用handler传递数据
//在handler发送数据之前,注意需要先开启fragment。
//否则handler变量一直为空 此handler变量是fragment调用setHandler()传来的。
if (handler == null) {
return;
}
Message message = new Message();
bundle.putString(SaveData1, number1);
bundle.putString(SaveData2, number2);
message.setData(bundle);
handler.sendMessage(message);
Activity中暴露的Setter方法:
//设置handler对象 由fragment调用
public void setHandler(Handler handler) {
this.handler = handler;
}
Fragment中要接收数据,所以要注册一个Handler来接收Message。同时,还要将handler对象设置给Activity。
onAttach中的activity是在基类BaseFragment中设置的,子类直接用了。
activity = (FrgmentActivity) context; //防止getActivity()空指针
@Override
public void onAttach(Context context) {
super.onAttach(context);
//设置Activity的handler对象
//为的是 activity和fragment使用同一个handler对象 才能进行handler通信
activity.setHandler(handler);
}
//定义handler 用于接收消息 接收activity传递来的数据
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String number1 = bundle.getString("number1");
String number2 = bundle.getString("number2");
//进行数据操作
textResult.setText(doAddition(number1, number2));
}
};
因为要在Fragment的生命周期onAttach中设置Activity的handler对象,所以传递数据发送消息,一定要在Fragment加载之后,即生命周期从onAttach走到onResume。否则Activity中的handler对象始终为null。
广播有很多用处,当然也可以用在这里。Activity向Fragment通信,则在Activity中发送广播,在Fragment中接收广播。
Activity中发送广播:
//3.使用广播传递数据
Intent intent = new Intent();
intent.setAction(ACTION_NAME);
intent.putExtra(SaveData1, number1);
intent.putExtra(SaveData2, number2);
//sendBroadcast(intent);
//使用本地广播更加安全
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Fragment中接收广播:
public class Fragment3 extends BaseFragment {
private MyReceiver myReceiver;
@Override
public void onResume() {
super.onResume();
myReceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(activity.ACTION_NAME);
//注册广播
//activity.registerReceiver(myReceiver, intentFilter);
LocalBroadcastManager.getInstance(activity).registerReceiver(myReceiver, intentFilter);
}
@Override
public int setFragmentLayoutID() {
return R.layout.fragment_fragment3;
}
//创建广播接收实例
class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//获取数据
String number1 = intent.getStringExtra(activity.SaveData1);
String number2 = intent.getStringExtra(activity.SaveData2);
//进行数据操作
textResult.setText(doAddition(number1, number2));
}
}
@Override
public void onPause() {
super.onPause();
//取消注册广播
//activity.unregisterReceiver(myReceiver);
LocalBroadcastManager.getInstance(activity).unregisterReceiver(myReceiver);
}
}
EventBus是一款针对Android优化的发布/订阅事件总线。简化了应用程序内各组件间、组件与后台线程间的通信。
EventBus详细介绍请移步: Android事件总线(一)EventBus3.0用法全解析
首先添加依赖:
implementation 'org.greenrobot:eventbus:3.0.0'
Activity向Fragment中传递数据:(Fragment->Activity调换位置即可)
Fragment中要接收数据,首先要在Fragment中注册和注销EventBus:
@Override
public void onResume() {
super.onResume();
//注册EventBus,注意参数是this,传入activity会报错
EventBus.getDefault().register(this);
}
@Override
public void onPause() {
super.onPause();
//取消EventBus注册
EventBus.getDefault().unregister(this);
}
还应该有一个接收数据,处理数据的函数。
//EventBus的处理事件函数 该方法可以随意取名 必须为public 必须添加注解并指定线程模型
//之后EventBus会自动扫描到此函数,进行数据传递
@Subscribe(threadMode = ThreadMode.MAIN)
public void getData(Bundle bundle) {
String number1 = bundle.getString(activity.SaveData1);
String number2 = bundle.getString(activity.SaveData2);
//进行数据操作
textResult.setText(doAddition(number1, number2));
}
Activity在响应事件中打包数据,数据复杂的话可以专门封装一个实体类,我的数据简单,直接用Bundle封装了。
//4.使用EventBus 向fragment传递数据
//利用bundle打包数据,也可自己封装Event事件
bundle.putString(SaveData1, number1);
bundle.putString(SaveData2, number2);
//发送数据
EventBus.getDefault().post(bundle);
是不是很简单。
接口的方式懒得写了,就是Fragment声明一个接口,然后Activity实现接口。(反之亦然)
各个方式优缺点以及大神封装的接口框架,参考:Android:Activity与Fragment通信(99%)完美解决方案
~~年底了,公司over了,突然就下岗了(# ̄~ ̄#),希望自己能找到更好的工作。
待随时补充,修正。