第8章 Fragment碎片化开发:从入门到精通
Fragment,说白了就是Activity里的“碎片”。你可以把它理解成一个小型的、可复用的模块化界面。我刚开始学Android时,总觉得Fragment是个多余的东西——一个Activity不就能搞定一切吗?直到我接手了一个需要同时适配手机和平板的项目,才明白Fragment有多香。
8.1 Fragment的生命周期
Fragment的生命周期比Activity复杂一些。它依附于Activity,所以Activity的生命周期变化会直接影响Fragment。但Fragment自己也有独立的回调方法。
| 回调方法 | 说明 |
|---|---|
| onAttach() | Fragment与Activity建立关联时调用 |
| onCreate() | Fragment被创建时调用,适合初始化数据 |
| onCreateView() | 创建Fragment的视图层次时调用 |
| onActivityCreated() | Activity的onCreate()执行完毕后调用 |
| onStart() | Fragment可见时调用 |
| onResume() | Fragment可交互时调用 |
| onPause() | Fragment失去焦点时调用 |
| onStop() | Fragment不可见时调用 |
| onDestroyView() | Fragment的视图被销毁时调用 |
| onDestroy() | Fragment被销毁时调用 |
| onDetach() | Fragment与Activity解除关联时调用 |
核心要点:onCreateView()只负责创建视图,不要在这里做耗时操作。onActivityCreated()才是真正可以安全操作Activity控件的地方。
我的经验:我曾经在onCreateView()里直接调用了Activity的findViewById(),结果空指针异常。后来才明白,那时候Activity的布局还没完全加载完。嗯,这个坑我替你们踩过了。
8.2 静态加载与动态加载Fragment
静态加载,就是在布局文件里直接写
静态加载示例
<!-- activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/my_fragment"
android:name="com.example.MyFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
动态加载示例
// 在Activity中动态添加Fragment
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
MyFragment fragment = new MyFragment();
transaction.add(R.id.fragment_container, fragment);
transaction.commit();
注意:动态加载时,commit()必须在Activity保存状态之前调用,否则会抛出IllegalStateException。我建议使用commitAllowingStateLoss()来避免这个问题,但前提是你确定能接受状态丢失的风险。
8.3 Fragment与Activity通信
Fragment和Activity之间怎么传数据?说白了就三种方式:接口回调、Bundle传参、ViewModel共享。
接口回调(最推荐)
// 定义接口
public interface OnFragmentInteractionListener {
void onItemSelected(String data);
}
// Fragment中调用
public class MyFragment extends Fragment {
private OnFragmentInteractionListener listener;
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
listener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener");
}
}
private void sendDataToActivity(String data) {
if (listener != null) {
listener.onItemSelected(data);
}
}
}
Bundle传参(从Activity到Fragment)
// Activity中
Bundle bundle = new Bundle();
bundle.putString("key", "value");
MyFragment fragment = new MyFragment();
fragment.setArguments(bundle);
// Fragment中接收
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
String value = getArguments().getString("key");
}
}
避坑指南:我曾经直接用Fragment的构造函数传参,结果Activity重建后参数全丢了。记住,永远用setArguments()来传参,系统会帮你保存和恢复。
8.4 FragmentManager管理
FragmentManager是Fragment的总管家。它负责Fragment的添加、移除、替换、回退栈管理等操作。你想想看,没有它,Fragment就是一盘散沙。
// 获取FragmentManager
FragmentManager fm = getSupportFragmentManager();
// 开启事务
FragmentTransaction ft = fm.beginTransaction();
// 替换Fragment
ft.replace(R.id.container, new MyFragment());
// 添加到回退栈
ft.addToBackStack(null);
// 提交事务
ft.commit();
关键点:addToBackStack()会把当前事务加入回退栈,用户按返回键时可以回退到上一个Fragment状态。如果不加,按返回键就直接退出Activity了。
8.5 ViewPager + Fragment实现滑动页面
ViewPager配合Fragment,是实现左右滑动页面的经典组合。我做过一个新闻客户端,首页就是用的这个方案,用户体验非常好。
// 适配器
public class MyPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentList;
public MyPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragmentList = fragments;
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
}
// Activity中使用
ViewPager viewPager = findViewById(R.id.view_pager);
List<Fragment> fragments = new ArrayList<>();
fragments.add(new Page1Fragment());
fragments.add(new Page2Fragment());
fragments.add(new Page3Fragment());
MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager(), fragments);
viewPager.setAdapter(adapter);
性能提醒:FragmentPagerAdapter会把所有Fragment都保存在内存中,适合页面数量少的情况。如果页面很多(比如超过10页),建议用FragmentStatePagerAdapter,它只会保留当前页和相邻页,节省内存。
知识体系总览
Fragment这东西,说白了就是Android开发中的瑞士军刀。你用得好了,代码复用性、界面灵活性都能上一个台阶。我刚开始学的时候也觉得绕,但多做几个项目就发现,Fragment真的是现代Android开发的基石。
总结一下:生命周期要记牢,动态加载更灵活,通信用接口回调最稳妥,FragmentManager是总指挥,ViewPager+Fragment做滑动页面最顺手。把这些吃透了,你就能写出结构清晰、可维护性强的Android应用。