开发者>文档>指南>Fragment">Fragment碎片用法
Fragment是一种可以嵌入在活动中的UI片段,能够让程序更加合理和充分地利用大屏幕的空间,出现的初衷是为了适应大屏幕的平板电脑,可以将其看成一个小型Activity,又称作Activity片段。
- Fragment依赖于Activity,不能独立存在
- 一个Activity可以有多个Fragment
- 一个Fragment可以被多个Activity重用
- Fragment有自己的生命周期,并能接收输入事件
- 可以在Activity运行时动态地添加或删除Fragment
1、Fragment生命周期

onAttach():Fragment和Activity相关联时调用。通过该方法获取Activity引用,getArguments()获取参数。onCreate():Fragment被创建时调用onActivityCreated():当Activity完成onCreate()时调用onStart(): 当Fragment可见时调用。onResume(): 当Fragment可见且可交互时调用onPause(): 当Fragment不可交互但可见时调用。onStop(): 当Fragment不可见时调用。onDestroyView():当Fragment的UI从视图结构中移除时调用。onDestroy(): 销毁Fragment时调用。onDetach(): 当Fragment和Activity解除关联时调用。
2、定义Fragment
2.1、Fragment派生类
Android已经预定义了一些Fragment派生类。可以继承它们二次封装,增加、完善功能使用。
显示浮动对话框。使用此类创建对话框可有效代替使用 Activity 类中的对话框辅助方法,因为您可以将片段对话框纳入由 Activity 管理的片段返回栈,从而使用户能够返回清除的片段。
显示由适配器(如 SimpleCursorAdapter)管理的一系列项目,类似于 ListActivity。该类提供几种管理列表视图的方法,如用于处理点击事件的 onListItemClick() 回调。(请注意,显示列表的首选方法是使用 RecyclerView,而非 ListView。在此情况下,您需在列表布局中创建包含 RecyclerView 的片段。如需了解具体操作方法,请参阅使用 RecyclerView 创建列表)
以列表形式显示 Preference 对象的层次结构。此类用于为您的应用创建设置屏幕。参考另一篇《Android设置界面:PreferenceScreen 》④WebViewFragment deprecated in API level 28
显示WebView的片段。当片段暂停或恢复时,WebView将自动暂停和恢复。
2.2、自定义Fragment
继承Fragment或其派生类,重写onCreateView(),在方法中调用inflater.inflate()方法加载Fragment布局文件,接着返回加载的view对象
public class MyFragment extends Fragment {
@Override
public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.fragment, container, false);
}
}注意:
①inflate()的第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛如下异常:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
②创建Fragment时要传入参数,必须要通过setArguments(Bundle bundle)方式添加,而不建议通过为Fragment添加带参数的构造函数,因为通过setArguments()方式添加,在由于内存紧张导致Fragment被系统杀掉并恢复(re-instantiate)时能保留这些数据。
在Fragment的onAttach()中通过getArguments()获得传进来的参数。
③获取Activity对象,不建议调用getActivity(),而是在onAttach()中将Context对象强转为Activity对象
3、加载Fragment
3.1、静态加载:<fragment/>布局中指明
最直接的一种方式,添加<fragment />标签布局,使android:name 属性指定要在布局中进行实例化的 Fragment 类。静态加载添加后就不能在运行时删除。
<LinearLayout>
<fragment
android:id="@+id/fragment"
//指明替换此fragment的Fragment类
android:name=".fragment.MyFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>创建此 Activity 布局时,系统会将布局中指定的每个片段实例化,并为每个片段调用 onCreateView() 方法,以检索每个片段的布局。系统会直接插入片段返回的 View,从而代替 <fragment> 元素。
注意:每个片段都需要唯一标识符,重启 Activity 时,系统可使用该标识符来恢复片段(您也可以使用该标识符来捕获片段,从而执行某些事务,如将其移除)。可以通过两种方式为片段提供 ID:
- 为
android:id属性提供唯一 ID。 - 为
android:tag属性提供唯一字符串。
3.2、动态加载:FragmentManager+FrameLayout
布局中使用<FrameLayout/>标签先占位,需要指定id,不需要指定name。
<LinearLayout>
<FrameLayout
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>在Activity代码中,先getSupportFragmentManager()获取到FragmentManager
FragmentManager fragmentManager = getSupportFragmentManager();替换:replace(),先开启一个事务,替换,提交。
fragmentManager.beginTransaction()
.replace(R.id.fragment, new FirstFragment(), "My Fragment Tag")
.commit();添加:使用add()方法添加Fragment。会导致多个Fragment会重叠在一起。
fragmentManager.beginTransaction()
.add(R.id.fragment, new SecondFragment()
.commit();4、Fragment方法
操作Fragment,都是通过FragmentManager开启一个事务FragmentTransaction。
①FragmentTransaction.add()
Activity里面添加一个片段
public FragmentTransaction add(int containerViewId,Fragment fragment,String tag)第一个参数是根容器的id(FrameLayout的id,即”@id/container”),第二个参数是Fragment对象,第三个参数是fragment的tag名,指定tag的好处是后续我们可以通过Fragment1 frag = getSupportFragmentManager().findFragmentByTag("f1")从FragmentManager中查找Fragment对象。
注意:同一个Fragment对象,只能add一次,否则奔溃:
java.lang.IllegalStateException: Fragment already added: MyFragment{8fb7f5c (ed6589cc-db78-4e6c-ac7a-c78d088ad6c1) id=0x7f080069 My Fragment Tag}
②FragmentTransaction.replace()
另一个Fragment替换当前的,实际上是remove()然后add()的合体
③FragmentTransaction.remove()
从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁
④FragmentTransaction.hide()
隐藏当前Fragment,仅不可见,不会销毁
⑤FragmentTransaction.show()
显示之前隐藏的Fragment
⑥FragmentTransaction.detach()
会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。似乎detach之后不能再次添加到Fragment中
⑦FragmentTransaction.attach()
重建view视图
⑧FragmentTransaction.commit()
提交修改
⑨FragmentTransaction.addToBackStack()
将Fragment事务加入回退栈
⑩FragmentManager.findFragmentByTag()
从FragmentManager中查找Fragment对象
5、Fragment通信
Fragmen之间、Fragment和Activity之间如何通信?传递数据、信息。
5.1、Fragment->Acvtivity
Fragment向Activity传递信息,在Fragment中定义interface接口
public interface FragmentListener {
void notifyActivity();
}Activity实现该接口:
public class MyFragmentActivity extends AppCompatActivity implements MyFragment.FragmentListener{
...
@Override
public void notifyActivity() {
Log.d("QUIBBLER", "Fragment->Activity");
}
}在Fragment onAttach()的时候,通过Context也就是Activity,强转成定义的FragmentListener接口类型
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof FragmentListener) {
listener = (FragmentListener) context;
}这样就可以在Fragment中通过调用接口,Activity实现方法,与Activity通信。
listener.notifyActivity();这种方式定义接口再去实现,似乎有点繁琐。推荐一个注解工具,GitHub:FABridge
5.2、Activity->Fragment
比起前面的Fragment向Activity通信,Activity向Fragment通信就方便的多,毕竟站在Activity上帝视角可以看到所有Fragment。
直接在Activity中获取到对应Fragment对象,调用其中定义的方法即可。
5.3、Fragment<->Fragment
Fragment之间是没有任何依赖关系的,因此如果要进行Fragment之间的通信,建议通过Activity作为中介,不要Fragment之间直接通信。
6、Fragment退回栈
Android系统为Activity维护一个任务栈,Fragment的每次替换,添加,也是一条可寻“轨迹”。将每次Fragment的操作添加到Fragment退回栈中。
fragmentManager.beginTransaction()
.add(R.id.fragment_two, new MyFragment(), "My Fragment Tag")
.addToBackStack("MyFragment")
.commit();当用户按返回按钮的时候,不是直接退出当前Activity,而是一次按照Fragment的添加修改顺序,退回。Fragment完全从后退栈中弹出,用户再次点击后退键,则退出当前Activity。
手动从Fragment退回栈中弹出Fragment:popBackStackImmediate()或popBackStack()。这里根据前面添加入栈的String name进行pop,如果多个入栈,但是使用了同一个name,会一次性全部退出栈。所以这个字符串name,可以看做是入栈“车次”"一批"。与前面返回键不同(每返回一次,退回一个Fragment)
fragmentManager.popBackStackImmediate(BlankFragment.class.getSimpleName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
//或者
fragmentManager.popBackStack(BlankFragment.class.getSimpleName(), FragmentManager.POP_BACK_STACK_INCLUSIVE); Fragment还会和ViewPager经常一起使用,这时候就要用到FragmentPagerAdapter、FragmentStatePagerAdapter。参考《ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager 》
参考:
《Fragment懒加载实现,BaseFragment封装》
《Fragment 与 FragmentPagerAdapter》

