来源 Fragment的概念来源于Android3.0,主要目的是为大屏幕(如平板电脑)上更加动态和灵活的界面设计提供支持。他可添加到Activity中, 所以多个Activity可添加同一个Fragment,提高了代码复用性
。
生命周期
Fragment跟Activity的生命周期类似,不过只有在显示调用addToBackStack()
时,系统才会将片段放入由宿主 Activity 管理的返回栈。
生命周期方法 onCreate()
系统会在创建片段时调用此方法。当片段经历暂停或停止状态继而恢复后,
onCreateView()
系统会在片段首次绘制其界面时调用此方法。如要为片段绘制界面,从此方法中返回的 View 必须是片段布局的根视图。如果片段未提供界面,可以返回 null。
我们创建视图的方法。
onViewCreated
onCrateView执行后立即执行,此时可以获取view
onPause()
系统会将此方法作为用户离开片段的第一个信号(但并不总是意味着此片段会被销毁)进行调用。
onAttach()
在片段已与 Activity 关联时进行调用(Activity 传递到此方法内)。
onActivityCreated()
当 Activity 的 onCreate() 方法已返回时进行调用。此时可以进行fragment与activity的交换操作。
onDestroyView()
在移除与片段关联的视图层次结构时进行调用。
onDetach()
在取消片段与 Activity 的关联时进行调用。
Activity和Fragment的生命周期
Activity, Fragment和FragmentManager生命周期
注意点
注意生命周期的对应,比如Eventbus的注册和取消注册
事务 为什么Fragment需要事务呢?我的理解是,由于需要对Fragment进行添加、移除、替换等操作,那么FragmentManager
的出现是合适的,而FragmentManager
内部使用事务的方式来进行管理,就能保证各种操作的原子性
了。
基本用法
1 2 3 4 5 6 7 8 9 10 11 12 fragmentManager = getSupportFragmentManager(); transaction = fragmentManager.beginTransaction(); transaction.replace(R.id.testFragment, fragment); transaction.addToBackStack(null ); transaction.commit();
有几个注意点:
FragmentActivity和Fragment都有自己的FragmentManager
事务的操作 如何通信 可通过以下一些方式进行通信:
Framgnet中直接获取Activity的引用
Activity中通过FragmentManager获取对应Fragment的引用
通过函数回调
setArguments将参数传递给Fragment
共享ViewModel
Fragment Result API
直接获取引用 1 2 3 4 5 6 View listView = getActivity().findViewById(R.id.list);ExampleFragment fragment = (ExampleFragment) getSupportFragmentManager().findFragmentById(R.id.example_fragment);
这种方式虽然能方便的获取,但从代码设计的角度看是不合适的,耦合性
太高了
函数回调 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public static class FragmentA extends ListFragment { ... public interface OnArticleSelectedListener { public void onArticleSelected (Uri articleUri) ; } ... } public static class FragmentA extends ListFragment { OnArticleSelectedListener listener; ... @Override public void onAttach (Context context) { super .onAttach(context); try { listener = (OnArticleSelectedListener) context; } catch (ClassCastException e) { throw new ClassCastException (context.toString() + " must implement OnArticleSelectedListener" ); } } @Override public void onListItemClick (ListView l, View v, int position, long id) { Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id); listener.onArticleSelected(noteUri); } ... }
共享ViewModel 与宿主Activity通信 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class ItemViewModel extends ViewModel { private final MutableLiveData<Item> selectedItem = new MutableLiveData <Item>(); public void selectItem (Item item) { selectedItem.setValue(item); } public LiveData<Item> getSelectedItem () { return selectedItem; } } public class MainActivity extends AppCompatActivity { private ItemViewModel viewModel; @Override public void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); viewModel = new ViewModelProvider (this ).get(ItemViewModel.class); viewModel.getSelectedItem().observe(this , item -> { }); } } public class ListFragment extends Fragment { private ItemViewModel viewModel; @Override public void onViewCreated (@NonNull View view, Bundle savedInstanceState) { super .onViewCreated(view, savedInstanceState); viewModel = new ViewModelProvider (requireActivity()).get(ItemViewModel.class); ... items.setOnClickListener(item -> { viewModel.select(item); }); } }
将ViewModel放到同一范围,这样返回的是同一个ViewModel。
与其他Fragment通信 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class ListViewModel extends ViewModel { private final MutableLiveData<Set<Filter>> filters = new MutableLiveData <>(); private final LiveData<List<Item>> originalList = ...; private final LiveData<List<Item>> filteredList = ...; public LiveData<List<Item>> getFilteredList () { return filteredList; } public LiveData<Set<Filter>> getFilters () { return filters; } public void addFilter (Filter filter) { ... } public void removeFilter (Filter filter) { ... } } public class ListFragment extends Fragment { private ListViewModel viewModel; @Override public void onViewCreated (@NonNull View view, Bundle savedInstanceState) { super .onViewCreated(view, savedInstanceState); viewModel = new ViewModelProvider (requireActivity()).get(ListViewModel.class); viewModel.getFilteredList().observe(getViewLifecycleOwner(), list -> { }); } } public class FilterFragment extends Fragment { private ListViewModel viewModel; @Override public void onViewCreated (@NonNull View view, Bundle savedInstanceState) { viewModel = new ViewModelProvider (requireActivity()).get(ListViewModel.class); viewModel.getFilters().observe(getViewLifecycleOwner(), set -> { }); } public void onFilterSelected (Filter filter) { viewModel.addFilter(filter); } public void onFilterDeselected (Filter filter) { viewModel.removeFilter(filter); } }
父子Fragment通信 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class ListFragment extends Fragment { private ListViewModel viewModel; @Override public void onViewCreated (@NonNull View view, Bundle savedInstanceState) { viewModel = new ViewModelProvider (this ).get(ListViewModel.class); viewModel.getFilteredList().observe(getViewLifecycleOwner(), list -> { } } } public class ChildFragment extends Fragment { private ListViewModel viewModel; @Override public void onViewCreated (@NonNull View view, Bundle savedInstanceState) { viewModel = new ViewModelProvider (requireParentFragment()).get(ListViewModel.class); ... } }
Fragment Result API 在某些情况下,您可能要在 Fragment 之间或 Fragment 与其宿主 Activity 之间传递一次性值。则可以使用setFragmentResultListener。 它的原理是在getParentFragmentManager实现了观察者模式。
与其他Fragment通信
一旦 Fragment A 处于 STARTED 状态,它就会收到结果并执行监听器回调。
对于给定的键,只能有一个监听器和结果。如果您对同一个键多次调用 setFragmentResult(),并且监听器未处于 STARTED 状态,则系统会将所有待处理的结果替换为更新后的结果。如果您设置的结果没有相应的监听器来接收,则结果会存储在 FragmentManager 中,直到您设置一个具有相同键的监听器。监听器收到结果并触发 onFragmentResult() 回调后,结果会被清除。这种行为有两个主要影响:
返回堆栈上的 Fragment 只有在被弹出且处于 STARTED 状态之后才会收到结果。
如果在设置结果时监听结果的 Fragment 处于 STARTED 状态,则会立即触发监听器的回调。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @Override public void onCreate (@Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); getParentFragmentManager().setFragmentResultListener("requestKey" , this , new FragmentResultListener () { @Override public void onFragmentResult (@NonNull String requestKey, @NonNull Bundle bundle) { String result = bundle.getString("bundleKey" ); } }); } button.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View v) { Bundle result = new Bundle (); result.putString("bundleKey" , "result" ); getParentFragmentManager().setFragmentResult("requestKey" , result); } });
父子Fragment通信
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Override public void onCreate (@Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); getChildFragmentManager() .setFragmentResultListener("requestKey" , this , new FragmentResultListener () { @Override public void onFragmentResult (@NonNull String requestKey, @NonNull Bundle bundle) { String result = bundle.getString("bundleKey" ); } }); } button.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View v) { Bundle result = new Bundle (); result.putString("bundleKey" , "result" ); getParentFragmentManager().setFragmentResult("requestKey" , result); } });
与宿主Activity通信 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class MainActivity extends AppCompatActivity { @Override public void onCreate (@Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); getSupportFragmentManager().setFragmentResultListener("requestKey" , this , new FragmentResultListener () { @Override public void onFragmentResult (@NonNull String requestKey, @NonNull Bundle bundle) { String result = bundle.getString("bundleKey" ); } }); } }
参考资料