💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
### Fragment #### 1、谈一谈Fragment的生命周期? > * 参考回答: > * Fragment从创建到销毁整个生命周期中涉及到的方法依次为:onAttach()→onCreate()→ onCreateView()→onActivityCreated()→onStart()→onResume()→onPause()→onStop()→onDestroyView()→onDestroy()→onDetach(),其中和Activity有不少名称相同作用相似的方法,而不同的方法有: > * **onAttach()**:当Fragment和Activity建立关联时调用; > * **onCreateView()**:当Fragment创建视图调用,在onCreate之后; > * **onActivityCreated()**:当与Fragment相关联的Activity完成onCreate()之后调用; > * **onDestroyView()**:在Fragment中的布局被移除时调用; > * **onDetach()**:当Fragment和Activity解除关联时调用; > * **Fragment的生命周期与Activity的对应关系如下图** > * ![](https://img.kancloud.cn/f7/08/f70827d2bfa742cec6c4102b65992894_361x731.png) > * 推荐文章: > * [Android之Fragment优点](https://www.cnblogs.com/shaweng/p/3918985.html) #### 2、谈谈Activity和Fragment的区别? > * 参考回答: > * 相似点:都可包含布局、可有自己的生命周期 > * 不同点: > * Fragment相比较于Activity多出4个回调周期,在控制操作上更灵活; > * Fragment可以[在XML文件中直接进行写入](https://developer.android.google.cn/training/basics/fragments/creating#AddInLayout),也可以在Activity中动态添加; > * Fragment可以使用show()/hide()或者replace()随时对Fragment进行切换,并且切换的时候不会出现明显的效果,用户体验会好;Activity虽然也可以进行切换,但是Activity之间切换会有明显的翻页或者其他的效果,在小部分内容的切换上给用户的感觉不是很好; #### 3、Fragment中add与replace的区别(Fragment重叠) > * 参考回答:(add与replace是FragmentTransaction的方法,[在运行时为 Activity 添加 Fragment](https://developer.android.google.cn/training/basics/fragments/fragment-ui#AddAtRuntime),[替换 Fragment](https://developer.android.google.cn/training/basics/fragments/fragment-ui#Replace)) > * [add 和 replace 如何选择?](https://juejin.im/post/5e5cd8686fb9a07cbc269d10#heading-5) > * 在我们的`activity`中,我们有一个容器,其中装有`fragment`。 > * `add`只会将一个`fragment`添加到容器中。 假设您将`FragmentA`和`FragmentB`添加到容器中。 容器将具有`FragmentA`和`FragmentB`,如果容器是`FrameLayout`,则将`fragment`一个添加在另一个之上。 > * `replace`将简单地替换容器顶部的一个`fragment`,因此,如果我创建了 `FragmentC`并 `replace` 顶部的 `FragmentB`,则`FragmentB`将被从容器中删除(执行`onDestroy`,除非您调用`addToBackStack`,仅执行`onDestroyView`),而`FragmentC`将位于顶部。 > * 那么如何选择呢? `replace`删除现有`fragment`并添加一个新`fragment`。 这意味着当您按下返回按钮时,将创建被替换的`fragment`(原先就存在的`fragment`),并调用其`onCreateView`。 另一方面,`add`保留现有`fragment`,并添加一个新`fragment`,这意味着现有`fragment`将处于活动状态,并且它们不会处于 “paused” 状态。 因此,按下返回按钮时,现有`fragment`(添加新`fragment`之前的`fragment`)不会调用`onCreateView`。 就`fragment`的生命周期事件而言,在`replace`的情况下将调用`onPause`,`onResume`,`onCreateView`和其他生命周期事件,在`add`的情况下则不会。 > * 如果不需要重新访问当前`fragment`并且不再需要当前`fragment`,请使用`replace`。 另外,如果您的应用有内存限制,请考虑使用`replace`。 > * add不会重新初始化Fragment,replace每次都会。所以如果在Fragment生命周期内获取获取数据,使用replace会重复获取; > * 添加相同的Fragment时,replace不会有任何变化,add会报IllegalStateException异常; > * replace先remove掉相同id的所有Fragment,然后在add当前的这个Fragment,而add是覆盖前一个Fragment。所以如果使用add一般会伴随hide()和show(),避免布局重叠; > * 使用add,如果应用放在后台,或以其他方式被系统销毁,再打开时,hide()中引用的Fragment会销毁,所以依然会出现布局重叠bug,可以使用replace或使用add时,添加一个tag参数; ``` //Fragment布局重叠解决方案,方法不唯一,仅供参考 private int mCurrentPos=-1; private List<Fragment> mFragments =new ArrayList<>(); private void switchFragmentIndex(int position){ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); if(mCurrentPos !=-1){ transaction.hide(mFragments.get(mCurrentPos)); } if(!mFragments.get(position).isAdded()){//避免Fragment重复添加 transaction.add(R.id.fl_content,mFragments.get(position)); } transaction.show(mFragments.get(position)).commit(); mCurrentPos =position;//记录当前Fragment下标 } ``` #### 4、getFragmentManager(已弃用)、getSupportFragmentManager 、getChildFragmentManager、getParentFragmentManager之间的区别? > * 参考回答: > * [getSupportFragmentManager , getParentFragmentManager和getChildFragmentManager](https://juejin.im/post/5e5cd8686fb9a07cbc269d10#heading-1) > * 首先要确认一件事,`getSupportFragmentManager()`是 `FragmentActivity`下的方法 > * `getParentFragmentManager` 和 `getChildFragmentManager` 是 `androidx.fragment.app.Fragment` 下的方法,**其中 `androidx.fragment 1.2.0` 后 `getFragmentManager` 与 `requireFragmentManager` 已弃用** > * `getSupportFragmentManager`与 `activity`关联,可以将其视为 `activity` 的 `FragmentManager` > * `getChildFragmentManager` 与 `fragment`关联,可以将其视为`fragment`的`FragmentManager` > * `getParentFragmentManager`情况稍微复杂,正常情况返回的是该`fragment` 依附的`activity`的`FragmentManager`。如果该fragment是另一个`fragment` 的子 `fragment`,则返回的是其父`fragment`的 `getChildFragmentManager` > * getFragmentManager()所得到的是所在Fragment 的**父容器**的管理器, getChildFragmentManager()所得到的是在Fragment 里面**子容器**的管理器, 如果是Fragment嵌套Fragment,那么就需要利用getChildFragmentManager(); > * 推荐文章 > * [【背上Jetpack之Fragment】你真的会用Fragment吗?Fragment常见问题以及androidx下Fragment的使用新姿势](https://juejin.im/post/5e5cd8686fb9a07cbc269d10) > * [AndroidX 概览](https://developer.android.google.cn/jetpack/androidx) > * [迁移到 AndroidX](https://developer.android.google.cn/jetpack/androidx/migrate) > * [是时候迁移至 AndroidX 了!](https://mp.weixin.qq.com/s/ENVktd-2g3cwixVeUi33AA) > * [androidx中的fragment API](https://developer.android.google.cn/jetpack/androidx/releases/fragment) > * [androidx中的fragment API 版本 1.2.0](https://developer.android.google.cn/jetpack/androidx/releases/fragment#version\_120\_3) > * **弃用`getFragmentManager()`**:弃用了关于 Fragment 的`getFragmentManager()`和`requireFragmentManager()`方法,并替换为单个`getParentFragmentManager()`方法,后者会返回添加了 Fragment 的非 null`FragmentManager`(您可以使用`isAdded()`来确定是否可以安全调用该方法) #### 5、[FragmentPagerAdapter](https://www.androidos.net.cn/android/9.0.0_r8/xref/frameworks/support/fragment/src/main/java/androidx/fragment/app/FragmentPagerAdapter.java)与[FragmentStatePagerAdapter](https://www.androidos.net.cn/android/9.0.0_r8/xref/frameworks/support/fragment/src/main/java/androidx/fragment/app/FragmentStatePagerAdapter.java)的区别与使用场景 > * 参考回答: > * 相同点 :二者都继承PagerAdapter > * 不同点 : > * **FragmentPagerAdapter**的每个Fragment会持久的保存在FragmentManager中,只要用户可以返回到页面中,它都不会被销毁。因此适用于那些数据**相对静态**的页,Fragment**数量也比较少**的那种; **FragmentStatePagerAdapter**只保留当前页面,当页面不可见时,该Fragment就会被消除,释放其资源。因此适用于那些**数据动态性**较大、**占用内存**较多,多Fragment的情况; > * **FragmentPagerAdapter**将整个 `fragment`存储在内存中,如果`ViewPager`中使用了大量 `fragment`,则可能导致内存开销增加。 **FragmentStatePagerAdapter**仅存储片段的`savedInstanceState`,并在失去焦点时销毁所有 `fragment`。 > * 推荐文章 > * [FragmentStatePagerAdapter和 FragmentPagerAdapter](https://juejin.im/post/5e5cd8686fb9a07cbc269d10#heading-2)