第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

静态加载,就是在布局文件里直接写标签。动态加载,则是通过代码把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碎片化开发 生命周期 onCreate → onCreateView onStart → onResume onPause → onStop onDestroyView → onDestroy 加载方式 静态加载:布局中声明 动态加载:代码添加 通信方式 接口回调 Bundle传参 ViewModel共享 FragmentManager 添加、移除、替换 回退栈管理 ViewPager+Fragment FragmentPagerAdapter FragmentStatePagerAdapter 掌握Fragment = 掌握Android模块化开发的核心

Fragment这东西,说白了就是Android开发中的瑞士军刀。你用得好了,代码复用性、界面灵活性都能上一个台阶。我刚开始学的时候也觉得绕,但多做几个项目就发现,Fragment真的是现代Android开发的基石。

总结一下:生命周期要记牢,动态加载更灵活,通信用接口回调最稳妥,FragmentManager是总指挥,ViewPager+Fragment做滑动页面最顺手。把这些吃透了,你就能写出结构清晰、可维护性强的Android应用。

公众号:蓝海资料掘金营,微信deep3321