当前位置: 首页 > news >正文

Android开发-Fragment

一、什么是 Fragment?

1. 核心概念

  • Fragment 是一个可以嵌入在 Activity 中的 UI 片段。
  • 它拥有自己的布局、生命周期事件处理逻辑
  • 一个 Activity 可以包含多个 Fragment,一个 Fragment 也可以在多个 Activity 中复用。

2. 为什么使用 Fragment?

场景优势
大屏适配在平板上并排显示列表 + 详情页
Tab 切换ViewPager + Fragment 实现标签页
组件化将功能模块(如设置、消息)独立封装
状态保留横竖屏切换时自动保存 UI 状态

二、Fragment 的生命周期

Fragment 的生命周期比 Activity 更复杂,因为它依赖于宿主 Activity 并可能被动态添加/移除。

1. 生命周期图谱

onAttach() → onCreate() → onCreateView() → onActivityCreated()→ onStart() → onResume()↗ (用户交互) ↘
onPause() ← onStop() ← onDestroyView() ← onDestroy() ← onDetach()

2. 关键回调详解

方法说明注意事项
onAttach()Fragment 与 Activity 关联可获取 Activity 引用
onCreate()初始化 Fragment避免耗时操作
onCreateView()创建并返回 UI 布局inflate 布局文件
onViewCreated()View 创建完成初始化 View(如 findViewById)
onActivityCreated()Activity 的 onCreate() 完成可安全调用 Activity 方法
onStart() / onResume()可见、可交互类似 Activity
onPause() / onStop()不可见释放资源
onDestroyView()View 被销毁清理 View 相关资源(如 ButterKnife.unbind)
onDestroy()Fragment 销毁最终清理
onDetach()与 Activity 解除关联置空 Activity 引用

⚠️ 重点onDestroyView()onDestroy() 可能不同时触发。例如,replace() 操作会触发 onDestroyView() 但不立即触发 onDestroy()

三、创建与使用 Fragment

1. 定义 Fragment

public class NewsListFragment extends Fragment {private RecyclerView recyclerView;private NewsAdapter adapter;// 必须提供空参构造函数public NewsListFragment() {}@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {// 加载布局return inflater.inflate(R.layout.fragment_news_list, container, false);}@Overridepublic void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);// 初始化 ViewrecyclerView = view.findViewById(R.id.recycler_view);adapter = new NewsAdapter();recyclerView.setAdapter(adapter);recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));loadData();}private void loadData() {// 模拟加载数据List<News> newsList = NewsRepository.getNews();adapter.submitList(newsList);}
}

2. 在 Activity 中静态添加(不推荐)

<!-- activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><fragmentandroid:name="com.example.NewsListFragment"android:id="@+id/fragment_news"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>

缺点:无法动态管理,不灵活。

四、动态管理 Fragment(推荐)

使用 FragmentManagerFragmentTransaction 动态添加、替换、移除 Fragment。

1. 在 Activity 布局中预留容器

<FrameLayoutandroid:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="match_parent" />

2. 使用 FragmentTransaction

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);if (savedInstanceState == null) {// 首次创建,添加 FragmentgetSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new NewsListFragment()).commit();}}
}

3. 常用操作

FragmentManager fm = getSupportFragmentManager();// 添加
fm.beginTransaction().add(R.id.container, fragment).commit();// 替换(常用)
fm.beginTransaction().replace(R.id.container, newFragment).addToBackStack("tag") // 加入返回栈.commit();// 移除
fm.beginTransaction().remove(fragment).commit();// 隐藏/显示(切换)
fm.beginTransaction().hide(fragment1).show(fragment2).commit();

最佳实践

  • 使用 replace() 实现页面切换。
  • 调用 addToBackStack() 实现返回键导航。
  • 调用 commit() 提交事务。

五、Fragment 之间的通信

Fragment 不应直接相互调用,应通过 宿主 ActivityViewModel 进行通信。

方案 1:通过 Activity 通信(传统方式)

(1) 定义接口
public interface OnNewsSelectedListener {void onNewsSelected(News news);
}
(2) Fragment 中触发事件
// NewsListFragment.java
private OnNewsSelectedListener listener;@Override
public void onAttach(@NonNull Context context) {super.onAttach(context);if (context instanceof OnNewsSelectedListener) {listener = (OnNewsSelectedListener) context;} else {throw new RuntimeException(context + " must implement OnNewsSelectedListener");}
}// 在点击时调用
listener.onNewsSelected(selectedNews);
(3) Activity 实现接口并转发
public class MainActivity extends AppCompatActivity implements OnNewsSelectedListener {@Overridepublic void onNewsSelected(News news) {NewsDetailFragment detailFragment = NewsDetailFragment.newInstance(news);getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, detailFragment).addToBackStack(null).commit();}
}

方案 2:使用 ViewModel(推荐 - Jetpack)

(1) 创建共享 ViewModel
public class SharedViewModel extends ViewModel {private final MutableLiveData<News> selectedNews = new MutableLiveData<>();public LiveData<News> getSelectedNews() {return selectedNews;}public void selectNews(News news) {selectedNews.setValue(news);}
}
(2) Fragment 中观察数据
// NewsDetailFragment.java
public class NewsDetailFragment extends Fragment {private SharedViewModel viewModel;@Overridepublic void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);viewModel.getSelectedNews().observe(getViewLifecycleOwner(), news -> {if (news != null) {displayNews(news);}});}
}
(3) 另一个 Fragment 发送数据
// NewsListFragment.java
viewModel.selectNews(selectedNews); // 发送选中新闻

优势:解耦、生命周期安全、支持配置变更。

六、与 Jetpack Navigation 集成

现代 Android 开发推荐使用 Navigation 组件统一管理 Fragment 导航。

1. 添加依赖

implementation "androidx.navigation:navigation-fragment:2.7.7"
implementation "androidx.navigation:navigation-ui:2.7.7"

2. 定义导航图(nav_graph.xml)

<navigation xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/nav_graph"app:startDestination="@id/newsListFragment"><fragmentandroid:id="@+id/newsListFragment"android:name="com.example.NewsListFragment"android:label="新闻列表"><actionandroid:id="@+id/action_to_detail"app:destination="@id/newsDetailFragment" /></fragment><fragmentandroid:id="@+id/newsDetailFragment"android:name="com.example.NewsDetailFragment"android:label="新闻详情" />
</navigation>

3. 使用 Navigation Controller

// 在 Fragment 中跳转
findNavController().navigate(R.id.action_to_detail);// 带参数跳转
Bundle bundle = new Bundle();
bundle.putParcelable("news", selectedNews);
findNavController().navigate(R.id.action_to_detail, bundle);

七、最佳实践与避坑指南

  1. 永远不要在 Fragment 构造函数中传递参数
    ✅ 使用 newInstance() 静态工厂方法:

    public static NewsDetailFragment newInstance(News news) {Bundle args = new Bundle();args.putParcelable("news", news);NewsDetailFragment fragment = new NewsDetailFragment();fragment.setArguments(args);return fragment;
    }
  2. 使用 requireContext() / requireActivity()
    替代 getContext() / getActivity(),避免空指针。

  3. onDestroyView() 中清理 View 引用
    防止内存泄漏。

  4. 使用 ViewLifecycleOwner
    观察 LiveData 时使用 getViewLifecycleOwner() 而非 getLifecycleOwner()

  5. 避免在 onCreate() 中执行耗时操作

八、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

http://www.dtcms.com/a/415389.html

相关文章:

  • 等额本息年利率反推方法
  • 电商网站建设需要开原网站开发
  • 网站推广服务合同中国建筑集团有限公司电话
  • 全国金融许可证失控情况数据(邮政储蓄网点 / 财务公司等)2007.7-2025.7
  • 基于STM32与influxDB的电力监控系统-5
  • 太原做app网站建设推广普通话奋进新征程宣传语
  • 【Day 65】Linux-ELK
  • 怎么免费建立自己的网站平台站长之家
  • 韩国网站购物页游最火的游戏
  • 易语言如何做验证系统官方网站推广注册app赚钱平台
  • 雅安建设机械网站百度搜索风云榜排行榜
  • 2.2 传输介质 (答案见原书 P45)
  • 做ftp网站怎么设置淘客免费交易网站建设
  • ESLint - JavaScript 代码检查工具
  • 小企业网站制作w3c网站代码标准规范
  • Jenkins 全面精通指南:从入门到脚本大师
  • 电子商务网站开发策划网页设计师属于什么部门
  • Kafka 面试题及详细答案100道(81-90)-- 高级特性与应用
  • 便捷网站建设哪家好制作网站免费
  • 蜘蛛云建站网站淘宝关键词怎么选取
  • 商务类网站哪些网络公司可以做机票预订网站
  • 【网络】测试 IP 端口连通性方法总结
  • 网站开发的总结vs2015做网站
  • 【Coze】【视频】育儿书籍工作流
  • 巫山做网站那家好银行软件开发工资一般多少
  • 计算机视觉(opencv)——基于 dlib 实现图像人脸检测
  • 电子商城网站开发价格网站开发难不难
  • Coze源码分析-资源库-删除数据库-后端源码-流程/核心技术/总结
  • 在线买房网站建设 方案做电子商务网站需要什么软件
  • 夫妻分房睡,男人忍耐得越久越暴露一个真相!别不信!