1.通过Activity拿到FragmentManager,通过FragmentManager调用findFragmentById("ID")或者ByTag(),但是前提是这个Fragment有Tag
//通过Activity拿到FragmentManager
public void showPro(String key) {
list = map.get(key);
adapter = new ArrayAdapter(getActivity(),android.R.layout.simple_list_item_1, list);
lv.setAdapter(adapter);
}
//通过FragmentManager调用findFragmentById("ID")
ContentFragment cf = (ContentFragment) getActivity() .getFragmentManager().findFragmentById(R.id.content_fg);
cf.showPro(name);
2.使用接口通过getActivity()获取到当前依附的Activity,然后强转成具体的Activity,调用activity方法,获取到想要的Fragment,然后进行传值,通过setArguments()或者是直接调用方法
//首先在Fragment中定义一个接口
public interface showPro {
public void showProByName(String name);
}
//然后定义一个接口变量:
private showPro mCallback;
//我们要在宿主Activity中实现这个接口,这样当Fragment调用onAttach方法时我们就可以实例化这个接口了
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity != null) {
mCallback = (showPro) activity;
}
}
3.如果fragment不多的话,用广播传值,最好不要使用Handler,耦合比较高,处理不好容易内存泄漏,无法获取activity返回值
//左边Fragment中发送广播:
Intent intent = new Intent("showPro");
intent.putExtra("name", name);
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
//在右边Fragment中接收广播:
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(getActivity());
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("showPro");
BroadcastReceiver br = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String key = intent.getStringExtra("name");
list = map.get(key);
adapter = new ArrayAdapter(getActivity(),
android.R.layout.simple_list_item_1, list);
lv.setAdapter(adapter);
}
};
localBroadcastManager.registerReceiver(br, intentFilter);
4.EventBus传值,采用反射机制,造成性能问题,无法获取activity的返回值,普通接口,用于少量fragment中
//在activity中注册EventBus来接收
@Override
protected void onResume() {
super.onResume();
//在onResume中注册,在可交互状态下占用更少内存
EventBus.getDefault().register(this);
}
@Override
protected void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
}
//在fragment中响应事件发送msg
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//利用EventBus发送
EventBus.getDefault().post("我是Four用EventBus传递的数据");
}
});
//在activity接收事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void getFragmentMsg(String msg){
tvMain.setText(msg+MainActivity.class.getName());
}
5.使用Fragment 新的 API在俩个Fragment之间通信, 可以使用它们公共的 FragmentManager,它充当 Frrgament 之间传递数据的中心存储,setFragmentResult() 和 setFragmentResultListener()
虽然使用了 Fragment result APIs,替换了过时的 Fragment target APIs,但是新的 APIs 在Bundle 作为数据传传递方面有一些限制,只能传递简单数据类型、Serializable 和 Parcelable 数据,Fragment result APIs 允许程序从崩溃中恢复数据,而且不会持有对方的引用,避免当 Fragment 处于不可预知状态的时,可能发生未知的问题
接受数据
//如果在 FragmentA 中注册 FragmentResultListener 接受数据,你可以模拟 parent FragmentManager 发送数据
//如果在 FragmentA 中正确注册了 listener,可以用来验证 FragmentA 是否能收到数据,例如,如果在 FragmentA 中接受数据并更新 UI, 可以使用 Espresso APIs 来验证是否期望的数据
@Test
fun shouldReceiveData() {
val scenario = FragmentScenario.launchInContainer(FragmentA::class.java)
// Pass data using the parent fragment manager
scenario.onFragment { fragment ->
val data = bundleOf(KEY_DATA to "value")
fragment.parentFragmentManager.setFragmentResult("aKey", data)
}
// Verify data is received, for example, by verifying it's been displayed on the UI
onView(withId(R.id.textView)).check(matches(withText("value")))
}
发送数据
//可以在 FragmentB 的 parent FragmentManager 上注册一个 FragmentResultListener 来测试 FragmentB 是否成功发送数据,当发送数据结束时,可以来验证这个 listener 是否能收到数据
@Test
fun shouldSendData() {
val scenario = FragmentScenario.launchInContainer(FragmentB::class.java)
// Register result listener
var receivedData = ""
scenario.onFragment { fragment ->
fragment.parentFragmentManager.setFragmentResultListener(
KEY,
fragment,
FragmentResultListener { key, result ->
receivedData = result.getString(KEY_DATA)
})
}
// Send data
onView(withId(R.id.send_data)).perform(click())
// Verify data was successfully sent
assertThat(receivedData).isEqualTo("value")
}
6.ViewModel
在 Fragment 之间共享数据
Activity中的两个或更多 Fragment 需要相互通信是一种很常见的情况。想象一下主从 Fragment 的常见情况,假设您有一个 Fragment,在该 Fragment 中,用户从列表中选择一项,还有另一个 Fragment,用于显示选定项的内容。这种情况不太容易处理,因为这两个 Fragment 都需要定义某种接口描述,并且所有者 Activity 必须将两者绑定在一起。此外,这两个 Fragment 都必须处理另一个 Fragment 尚未创建或不可见的情况。
可以使用ViewModel
对象解决这一常见的难点。这两个 Fragment 可以使用其 Activity 范围共享ViewModel
来处理此类通信,如以下示例代码所示:
public class SharedViewModel extends ViewModel {
private final MutableLiveData- selected = new MutableLiveData
- ();
public void select(Item item) {
selected.setValue(item);
}
public LiveData
- getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
model.getSelected().observe(getViewLifecycleOwner(), { item ->
// Update the UI.
});
}
}
7.Fragment直接调用Activity中的public方法
//fragment中
((MainActivity) getActivity()).showProByName(name);
//activity中
@Override
public void showProByName(String name) {
cf.showPro(name);
}
public void showPro(String key) {
list = map.get(key);
adapter = new ArrayAdapter(getActivity(),android.R.layout.simple_list_item_1, list);
lv.setAdapter(adapter);
}
8.用FragmentManager获取到Fragment的集合getFragments(),然后手动遍历判断集合的Fragment是否需要Fragment,然后setArguments()或者是直接调用方法传值,但是这种方法不推荐
//获取集合
Listlist=(List)NewsFragment.this.getFragmentManager().getFragments();
//遍历集合
for(Fragment f:list){
if(f!=null&&f instanceof ShouYeMainFragment){
((ShouYeMainFragment) f).changView();
break;
}
}