1.通過(guò)Activity拿到FragmentManager笑撞,通過(guò)FragmentManager調(diào)用findFragmentById("ID")或者ByTag(),但是前提是這個(gè)Fragment有Tag
//通過(guò)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);
}
//通過(guò)FragmentManager調(diào)用findFragmentById("ID")
ContentFragment cf = (ContentFragment) getActivity() .getFragmentManager().findFragmentById(R.id.content_fg);
cf.showPro(name);
2.使用接口通過(guò)getActivity()獲取到當(dāng)前依附的Activity,然后強(qiáng)轉(zhuǎn)成具體的Activity,調(diào)用activity方法本谜,獲取到想要的Fragment痕寓,然后進(jìn)行傳值,通過(guò)setArguments()或者是直接調(diào)用方法
//首先在Fragment中定義一個(gè)接口
public interface showPro {
public void showProByName(String name);
}
//然后定義一個(gè)接口變量:
private showPro mCallback;
//我們要在宿主Activity中實(shí)現(xiàn)這個(gè)接口寒匙,這樣當(dāng)Fragment調(diào)用onAttach方法時(shí)我們就可以實(shí)例化這個(gè)接口了
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity != null) {
mCallback = (showPro) activity;
}
}
3.如果fragment不多的話(huà)零如,用廣播傳值,最好不要使用Handler锄弱,耦合比較高考蕾,處理不好容易內(nèi)存泄漏,無(wú)法獲取activity返回值
//左邊Fragment中發(fā)送廣播:
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傳值会宪,采用反射機(jī)制肖卧,造成性能問(wèn)題,無(wú)法獲取activity的返回值掸鹅,普通接口喜命,用于少量fragment中
//在activity中注冊(cè)EventBus來(lái)接收
@Override
protected void onResume() {
super.onResume();
//在onResume中注冊(cè),在可交互狀態(tài)下占用更少內(nèi)存
EventBus.getDefault().register(this);
}
@Override
protected void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
}
//在fragment中響應(yīng)事件發(fā)送msg
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//利用EventBus發(fā)送
EventBus.getDefault().post("我是Four用EventBus傳遞的數(shù)據(jù)");
}
});
//在activity接收事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void getFragmentMsg(String msg){
tvMain.setText(msg+MainActivity.class.getName());
}
5.使用Fragment 新的 API在倆個(gè)Fragment之間通信, 可以使用它們公共的 FragmentManager河劝,它充當(dāng) Frrgament 之間傳遞數(shù)據(jù)的中心存儲(chǔ)壁榕,setFragmentResult() 和 setFragmentResultListener()
雖然使用了 Fragment result APIs,替換了過(guò)時(shí)的 Fragment target APIs赎瞎,但是新的 APIs 在Bundle 作為數(shù)據(jù)傳傳遞方面有一些限制牌里,只能傳遞簡(jiǎn)單數(shù)據(jù)類(lèi)型、Serializable 和 Parcelable 數(shù)據(jù),F(xiàn)ragment result APIs 允許程序從崩潰中恢復(fù)數(shù)據(jù)牡辽,而且不會(huì)持有對(duì)方的引用喳篇,避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時(shí),可能發(fā)生未知的問(wèn)題
接受數(shù)據(jù)
//如果在 FragmentA 中注冊(cè) FragmentResultListener 接受數(shù)據(jù)态辛,你可以模擬 parent FragmentManager 發(fā)送數(shù)據(jù)
//如果在 FragmentA 中正確注冊(cè)了 listener麸澜,可以用來(lái)驗(yàn)證 FragmentA 是否能收到數(shù)據(jù),例如奏黑,如果在 FragmentA 中接受數(shù)據(jù)并更新 UI, 可以使用 Espresso APIs 來(lái)驗(yàn)證是否期望的數(shù)據(jù)
@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")))
}
發(fā)送數(shù)據(jù)
//可以在 FragmentB 的 parent FragmentManager 上注冊(cè)一個(gè) FragmentResultListener 來(lái)測(cè)試 FragmentB 是否成功發(fā)送數(shù)據(jù)炊邦,當(dāng)發(fā)送數(shù)據(jù)結(jié)束時(shí),可以來(lái)驗(yàn)證這個(gè) listener 是否能收到數(shù)據(jù)
@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 之間共享數(shù)據(jù)
Activity中的兩個(gè)或更多 Fragment 需要相互通信是一種很常見(jiàn)的情況熟史。想象一下主從 Fragment 的常見(jiàn)情況馁害,假設(shè)您有一個(gè) Fragment,在該 Fragment 中蹂匹,用戶(hù)從列表中選擇一項(xiàng)碘菜,還有另一個(gè) Fragment,用于顯示選定項(xiàng)的內(nèi)容限寞。這種情況不太容易處理忍啸,因?yàn)檫@兩個(gè) Fragment 都需要定義某種接口描述,并且所有者 Activity 必須將兩者綁定在一起履植。此外计雌,這兩個(gè) Fragment 都必須處理另一個(gè) Fragment 尚未創(chuàng)建或不可見(jiàn)的情況。
可以使用ViewModel
對(duì)象解決這一常見(jiàn)的難點(diǎn)静尼。這兩個(gè) Fragment 可以使用其 Activity 范圍共享ViewModel
來(lái)處理此類(lèi)通信,如以下示例代碼所示:
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> 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直接調(diào)用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()传泊,然后手動(dòng)遍歷判斷集合的Fragment是否需要Fragment鼠渺,然后setArguments()或者是直接調(diào)用方法傳值,但是這種方法不推薦
//獲取集合
List<Fragment>list=(List<Fragment>)NewsFragment.this.getFragmentManager().getFragments();
//遍歷集合
for(Fragment f:list){
if(f!=null&&f instanceof ShouYeMainFragment){
((ShouYeMainFragment) f).changView();
break;
}
}