[Android]Fragment与Activity之间的通信方案

Fragment依赖于Activity,那么它们之间的通信就必须要涉及。通过自己的寻找和实践,知道了Fragment和Activity之间的通信方案大概有5种,各有优缺点,用哪个方案看需求吧。

  1. setArguments(Bundle args)
  2. Handler
  3. Broadcast广播
  4. EventBus
  5. 接口回调

上代码,开始分析。自己写了个小Demo:Fragment通信Demo ,里边有上边前4种通信方式。  

demo中1、2、3为activity->fragment,2、3若要fragment->activiy则相关代码调换位置即可。4包含双向通信。

一、 setArguments(Bundle args)

 此方式还挺简单的,貌似是谷歌官方推荐的一种数据传递方式,如果遇到内存重启,系统会自动保存数据,和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);
    }
}

二、Handler方式

比如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。


三、Broadcast广播

广播有很多用处,当然也可以用在这里。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

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了,突然就下岗了(# ̄~ ̄#),希望自己能找到更好的工作。

待随时补充,修正。 

你可能感兴趣的:(Android)