文章目录
- 一、Activity向Fragment通信
- 1.1 通过方法
- 1.1.1 构造方法
- 1.1.1 普通public方法
- 1.2 通过setArguments方法
- 1.3 通过接口
- 二、Fragment向Activity通信
- 2.1 通过getActivity
- 2.2 通过接口
- 三、Fragment之间传递数据
- 通过Activity中转
一、Activity向Fragment通信
1.1 通过方法
1.1.1 构造方法
就是在MainActivity进行动态注册时,把data通过构造方法传参的形式传给fragment,所以要对fragment类进行修改
- 修改
Fragment
类
public class ExampleFragment2 extends Fragment {private static final String ARG_PARAM1 = "param1";private static final String ARG_PARAM2 = "param2";private String mParam1;private String mParam2;//保留空参构造public ExampleFragment2() {}//提供一个接收数据用的构造方法public ExampleFragment2(String param1) {mParam1 = param1;}//其他方法这里省略@Override// 在onViewCreated方法运行时,使用得到的数据public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);//获得mparam1的值后,修改textView的值if (!TextUtils.isEmpty(mParam1)) {TextView tv1 = view.findViewById(R.id.tv1);tv1.setText(mParam1);}}
}
onViewCreated
方法则是在视图创建完成后调用的,使用 onViewCreated
来处理视图相关的逻辑,确保视图已经完全创建并可用
- 在
Activity
中创建Fragment
实例
- 第一次创建时就传递
if (savedInstanceState == null) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();ExampleFragment2 fragment2 = new ExampleFragment2("这是我从碎片MainActivity传递的数据");fragmentTransaction.add(R.id.fragment_container2, fragment2).addToBackStack(null);fragmentTransaction.commit();}
- 创建后想再次传递
private void passDataByConstruct() {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();String data = "我的数据"ExampleFragment2 dataPassFragment = new ExampleFragment2(data);fragmentTransaction.replace(R.id.fragment_container2, dataPassFragment).commit();}
1.1.1 普通public方法
Fragment
类中添加普通方法
public void setParam(String data) {mParam1 = data;if (!TextUtils.isEmpty(mParam1)) {tv1.setText(mParam1);}}
- 在
Activity
中查找并调用Fragment
的普通方法
private void passDataByConstruct2() {FragmentManager fragmentManager = getSupportFragmentManager();Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container2);if (fragment != null) {((ExampleFragment2) fragment).setParam("我的数据2--普通方法");}
}
注意如果没使用点击事件的话,passDataByConstruct2
要在onResume
阶段被调用
1.2 通过setArguments方法
Bundle
是一个用于携带数据的键值对集合,它可以保存各种类型的数据,本身是一个实现了Parcelable
接口的类,因此它可以被序列化以便在组件之间传递。
- 在
Activity
中使用setArguments()
方法
public void onClick3(View view) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();// 创建一个新的ExampleFragment2实例ExampleFragment2 exampleFragment2 = new ExampleFragment2();// 创建一个Bundle对象,用于传递数据到新的片段Bundle bundle = new Bundle();// 向Bundle中添加字符串数据和整型数据bundle.putString("data", "我的数据3--Argument");bundle.putInt("int_data", 10);// 将Bundle对象设置为新的片段的参数exampleFragment2.setArguments(bundle);// 用新的片段替换布局中的片段容器,并提交此事务fragmentTransaction.replace(R.id.fragment_container2, exampleFragment2).commit();}
- 在
Fragment
使用getArguments()
接收数据
//部分方法省略
public class ExampleFragment2 extends Fragment {private String mParam1;private String mParam2;TextView tv1;// 用于存储从外部传入的额外数据private String data1;private int data2;// 在Fragment创建时调用 @Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (getArguments() != null) {mParam1 = getArguments().getString(ARG_PARAM1);mParam2 = getArguments().getString(ARG_PARAM2);// ----------------在这里---------------// 从参数中获取data1的值,这里"data""int_data"是键名 data1 = getArguments().getString("data");data2 = getArguments().getInt("int_data");}}@Overridepublic void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);tv1 = view.findViewById(R.id.tv1);//需要 在onViewCreated时进行修改,不然后tv1空指针异常if (!TextUtils.isEmpty(data1)) {tv1.setText(data1 + data2);}}
}
1.3 通过接口
利用观察者模式的思路实现
观察者模式是一种设计模式,涉及两个主要角色:
- 被观察者(Subject):维护一个观察者(Observer)列表,提供添加、移除观察者的方法,并在状态变化时通知所有观察者。
- 观察者(Observer):对被观察者感兴趣的对象,它们通过注册被观察者来接收通知。
MainActivity
作为被观察者
public class MainActivity extends AppCompatActivity {//fragment的动态注册省略public void onClick4(View view) {mDataChangeListener.onDataChange("我的数据4——接口");}//被观察者:数据源持有该引用private OnDataChangeListener mDataChangeListener;//这里接收的参数是任意实现了dataChangeListener接口的类的对象//目的是利用匿名内部类创建实现接口的对象来实现OnDataChangeListener方法public void setOnDataChangeListener(OnDataChangeListener dataChangeListener) {mDataChangeListener = dataChangeListener;}public interface OnDataChangeListener {void onDataChange(String data);}
}
mDataChangeListener
是一个接口引用,用于存储对某个实现了OnDataChangeListener
接口的对象的引用。setOnDataChangeListener(OnDataChangeListener)
方法允许外部对象(如ExampleFragment2
)注册自己为观察者,让MainActivity
能够在数据变化时通知它。onClick4(View view)
方法中调用mDataChangeListener.onDataChange()
方法,这表示数据发生了变化,通知所有注册的观察者。
存储回调对象:在实际使用中,mDataChangeListener
变量用于保存对某个对象(通常是匿名内部类或具体实现类)的引用,该对象提供了 onDataChange(String data)
方法的实现。这样,当数据发生变化时,我们可以通过这个变量来调用对应的实现,以通知数据变化。
ExampleFragment2
作为观察者
//其他方法省略
public class ExampleFragment2 extends Fragment {@Overridepublic void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);tv1 = view.findViewById(R.id.tv1);((MainActivity) getActivity()).setOnDataChangeListener(new MainActivity.OnDataChangeListener() {@Overridepublic void onDataChange(String data) {if (!TextUtils.isEmpty(data)) {tv1.setText(data);}}});}
}
- 在
onViewCreated()
方法中,ExampleFragment2
注册了自己为MainActivity
的观察者 - 通过调用
setOnDataChangeListener()
方法,ExampleFragment2
传入了一个匿名内部类,该类实现了OnDataChangeListener
接口 - 一旦
MainActivity
中调用onClick4(View view)
方法,ExampleFragment2
的onDataChange(String data)
方法被调用,从而更新界面(tv1.setText(data)
)
二、Fragment向Activity通信
2.1 通过getActivity
getActivity()
方法:返回当前
Fragment
正在附着的Activity
。它的返回类型是Activity
,如果Fragment
尚未附着到Activity
,则返回null
。
这样我们就可以通过附着的 Activity
调用它的方法,更新Activity
的UI或者传递数据‘
- 在
Activity
中使用
public class MainActivity extends AppCompatActivity {private TextView tv1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv1 = findViewById(R.id.tv1);//省略了该碎片的注册}public void setReceive(String data) {tv1.setText(data);}
- **在
Fragment
中使用getActivity
**传递数据
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);btn = view.findViewById(R.id.btn_pass_data1);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//强制类型转换为 MainActivity((MainActivity) getActivity()).setReceive("这是我从Fragment里传递过来的数据");}});
}
2.2 通过接口
依然是观察者模式
ExampleFragment2
作为被观察者
public class ExampleFragment2 extends Fragment {private Button btn2; @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); btn2 = view.findViewById(R.id.btn_pass_data2); btn2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 判断是否设置了数据变化监听器 if (mFragmentDataChangeListener != null) { // 如果设置了,则调用监听器的onFragmentDataChange方法,并传递数据 mFragmentDataChangeListener.onFragmentDataChange("这是我从Fragment里通过接口方法传递过来的数据"); } } }); } // 定义一个接口,用于Fragment向Activity传递数据时的回调 // 这是一种观察者模式的实现方式 public interface OnFragmentDataChangeListener { // 定义一个方法,当Fragment中的数据发生变化时,Activity可以通过此方法接收数据 void onFragmentDataChange(String data); } // 定义一个私有变量,用于存储实现了OnFragmentDataChangeListener接口的监听器 // 这个监听器通常由Activity实现并在Fragment与Activity关联时设置 private OnFragmentDataChangeListener mFragmentDataChangeListener; // 提供一个公开的方法,允许外部(如Activity)设置数据变化监听器 // 这样Fragment就可以在需要时通知Activity数据已经发生变化 public void setFragmentDataChangeListener(OnFragmentDataChangeListener fragmentDataChangeListener) { this.mFragmentDataChangeListener = fragmentDataChangeListener; }
}
MainActivity
作为观察者
public class MainActivity extends AppCompatActivity {private TextView tv1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv1 = findViewById(R.id.tv1);//第二个fragment动态注册的if (savedInstanceState == null) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();ExampleFragment2 fragment2 = new ExampleFragment2("这是我从碎片MainActivity传递的数据");fragmentTransaction.add(R.id.fragment_container2, fragment2);fragmentTransaction.commitNow();}// 获取FragmentManager,并尝试找到已经添加到指定容器的Fragment FragmentManager fragmentManager = getSupportFragmentManager(); Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container2); // 如果找到了Fragment,并且它确实是ExampleFragment2的实例,则设置数据变化监听器 if (fragment != null && fragment instanceof ExampleFragment2) { // 将MainActivity作为监听器,监听来自Fragment的数据变化 ((ExampleFragment2) fragment).setFragmentDataChangeListener(new ExampleFragment2.OnFragmentDataChangeListener() { // 当Fragment中的数据发生变化时,此方法会被调用 @Override public void onFragmentDataChange(String data) { // 更新TextView的文本为Fragment传递过来的数据 tv1.setText(data); }});}}
}
由于 Fragment 的添加和视图的渲染是异步的,所以这里可能为空,需要如下操作:
if (fragment != null)
防止空指针异常,确保在尝试访问或操作 Fragment 之前,它已经被正确加载和初始化。- 还要使用
commitNow()
提交事务 ,fragment
在接下来的findFragmentById()
调用中才有可能不为null
。
三、Fragment之间传递数据
通过Activity中转
由于Activity
是各个Fragment
的承载者,所以可以作为中间桥梁为各个Fragment
转递数据。
在
Fragment
中可以通过getActivity()
得到Activity
对象。
在Activity
中可以通过findFragmentByld
或者findFragmentByTag
找到指定的Fragment
,或者Fragment
作为
Activity
的成员变量直接使用。所以,一个
Fragment
先拿到其Activity
对象,再通过这个Activity
找到指定的Fragment
对象,然后调用其方法,从而传递数据
我这里有两个碎片在MainActivity上放着,并且他们各自都有一个按钮和文本,按钮用来发送数据,文本用来接收显示数据
ExampleFragment1
中按钮的点击事件
// 设置按钮的点击监听器
btn1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 获取当前活动的实例,并通过它的 FragmentManager 查找指定 ID 的 FragmentFragment fragment = ((MainActivity) getActivity()).getSupportFragmentManager().findFragmentById(R.id.fragment_container2);// 检查找到的 Fragment 是否为非空if (fragment != null) {// 如果 Fragment 不为空,将数据传递给它// 强制将 Fragment 转换为 ExampleFragment2 类型,并调用 setData 方法传递数据((ExampleFragment2) fragment).setData("这是我从碎片1传递来的数据");}}
});
ExampleFragment2
中方法,用来让ExampleFragment1
设置2中的文本
public void setData(String data) {if (tvReceiveData != null) {tvReceiveData.setText(data);}
}
if (fragment != null) {// 如果 Fragment 不为空,将数据传递给它// 强制将 Fragment 转换为 ExampleFragment2 类型,并调用 setData 方法传递数据((ExampleFragment2) fragment).setData("这是我从碎片1传递来的数据");}
}
});
`ExampleFragment2`中方法,用来让`ExampleFragment1`设置2中的文本```java
public void setData(String data) {if (tvReceiveData != null) {tvReceiveData.setText(data);}
}
这样就实现了ExampleFragment1
向ExampleFragment2
传递数据,2向1也是一样的
感谢您的阅读
如有错误烦请指正
参考:
- 35.5-Fragment之间数据传递1_哔哩哔哩_bilibili