本文已参与「新人创作礼」活动,一起开启掘金创作之路。
Android基础知识梳理-模块化布局Fragment
定义
Fragment是用于交互界面复用的组件。Fragment可以管理并定义自己的界面布局,有自己的生命周期,并且还可以处理自己的响应事件。但Fragment不能独立存在,必须依托于Activity和另一个Fragment管理。其视图层次结构会成为宿主的一部分或者附加到宿主的视图层级结构中。
特性
-
Fragment需要依托于Activity来管理,同时也可以在Fragment中添加新的Fragment;
-
Fragment用于界面模块化布局,可以将一个Activity划分为离散的区块,从而将模块化和可重用性引入到Activity中;
-
在Activity处于
Started状态时,可以新建、替换或移除Fragment,便于在运行时修改Activity的外观; -
可以在同一个Activity或者多个Activity使用同一个Fragment的多个实例,同时也可以用作另一个Fragment的子布局。
使用方法
1.创建Fragment
class ExampleFragment extends Fragment {
public ExampleFragment() {
super(R.layout.example_fragment);
}
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
int someInt = requireArguments().getInt("some_int");
...
}
}
2.添加Fragment
(1)静态方式
<!-- res/layout/example_activity.xml -->
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.ExampleFragment" />
(2)动态方式
<!-- res/layout/example_activity.xml -->
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
public class ExampleActivity extends AppCompatActivity {
public ExampleActivity() {
super(R.layout.example_activity);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
Bundle bundle = new Bundle();
bundle.putInt("some_int", 0);
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.add(R.id.fragment_container_view, ExampleFragment.class, bundle)
.commit();
}
}
}
3.Fragment管理器
FragmentManager 类负责对应用的 Fragment 执行一些操作,如添加、移除或替换它们,以及将它们添加到返回堆栈。
-
每个
FragmentActivity及其子类(如AppCompatActivity)都可以通过getSupportFragmentManager()方法访问FragmentManager。 -
Fragment 也能够托管一个或多个子 Fragment。在 Fragment 内,可以通过
getChildFragmentManager()获取对管理 Fragment 子级的FragmentManager的引用。如果需要访问其宿主FragmentManager,可以使用getParentFragmentManager()。
可以使用findFragmentById()和findFragmentByTag获取Fragment
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, ExampleFragment.class, null)
.setReorderingAllowed(true)
.addToBackStack(null)
.commit();
...
ExampleFragment fragment =
(ExampleFragment) fragmentManager.findFragmentById(R.id.fragment_container);
4.通信方式
-
ViewModel
Fragment可以通过宿主Activity中创建的ViewModel与Activity通信,同时也可以与其他Fragment通过Activity中共享的ViewModel进行通信,ViewModelProvider构造函数中指定了数据范围,只有属于同一数据范围才可以共享
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 -> {
// Update the list UI
});
}
}
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 -> {
// Update the selected filters UI
});
}
public void onFilterSelected(Filter filter) {
viewModel.addFilter(filter);
}
public void onFilterDeselected(Filter filter) {
viewModel.removeFilter(filter);
}
}
-
使用 Fragment Result API 获取结果
通过不同方式获取到的FragmentManager,Fragment可以与Activity或者其他Fragment使用FragmentManager的result API来进行通信。
在FragmentA中设置结果监听器
@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) {
// We use a String here, but any type that can be put in a Bundle is supported
String result = bundle.getString("bundleKey");
// Do something with the result
}
});
}
在FragmentB中使用同一个requestKey设置结果
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle result = new Bundle();
result.putString("bundleKey", "result");
getParentFragmentManager().setFragmentResult("requestKey", result);
}
});
Fragment生命周期
- onAttach:当Fragment与Activity发生关联时调用
- onCreate:创建Fragment时被回调,经历暂停或停止状态继而恢复后,想保留Fragment的基本组件,则在此进行初始化
- onCreateView:首次绘制页面时候调用,在此可以创建View,也可以返回null,这样不建议耗时操作
- onActivityCreated:Fragment绑定Activity,在onCreate方法已经执行完成并返回,在该方法内可以进行与Activity交互的UI操作,不能在此之前跟Activity进行交互
- onStart:启动 Fragment 时被回调,此时Fragment可见,只是还没有在前台显示,因此无法与用户进行交互
- onResume:Fragment在前台可见,处于活动状态,用户可与之交互
- onPause:Fragment处于暂停状态,但依然可见,用户不能与之交互
- onStop:停止Fragment回调,Fragment完全不可见
- onDestoryView:销毁与Fragment有关的视图,但未与Activity解除绑定
- onDestory:销毁 Fragment 时被回调,通常按Back键退出或者Fragment被回收时调用此方法,此后接onDetach
- onDetach:与onAttach相对应,当Fragment与Activity关联被取消时调用