- Android 开发之使用 Web Service 进行网络编程
- Android 开发之获取所有软件信息
- Android 开发之 Fragment 详解(一)
- Android 开发之解析 XML 并实现三级联动效果
- Android 网络编程之获取网络上的 XML
- Android 网络编程之获取网络上的 Json
- Android 网络编程之传递数据给服务器(一)
- Android 网络编程之传递数据给服务器(二)
- XML,Object,Json 转换之浅析 Xstream 的使用
- Json 与 Java 对象互转之 Gson 学习
- Android 网络编程之使用 HttpClient 批量上传文件(一)
- Android 图片压缩技巧
Android 开发之 Fragment 详解(一)
Android 开发之 Fragment 学习
1.简介:
Fragment 是 Android 3.0 引入的新 API。 Fragment 代表了 Activity 的子模块,因此可以把 Fragment 理解成 Activity 片段。Fragment 用于自己的生命周期,也可以接受它自己的输入事件。
Fragment 必须被 嵌入 Activity 中使用,因此虽然 Fragment 也拥有自己的生命周期,但 Fragment 的生命周期会受它所在的 Activity 的生命周期的控制。例如,当 Activity 暂停时,该 Activity 内的所有 Fragment 都会暂停;当 Activity 被销毁时,该 Activity 内的所有 Fragment 都会被销毁,只有当该 Activity 处于活动状态时,程序员可通过方法独立地操作 Fragment。
2.Fragment 的几个特征:
1)Fragment 总是作为 Activity 界面的组成部分,Fragment 可调用 getActivity() 方法获取它所在的 Activity, Activity 调用 FragmentManager 的 findFragmentByld() 或 findFragmentByTag() 方法来获取 Fragment。
2) 在 Activity 运行过程中,可调用 FragmentManager 的 add()、remove()、replace() 方法动态地添加、删除或替换 Fragment。
3)—个 Activity 可以同时组合多个 Fragment;反过来,一个 Fragment 也可被多 Activity 复用。
4)Fragment 可以响应自己的输入事件,并拥有自己的生命周期,但它们的生命周期直接被其所属的 Activity 的生命周期控制。
Android 3.0 引入 Fragment 的初衷是为了适应大屏幕的平板电脑,由于平板电脑的屏幕比手机屏蒂更大,因此可以容纳更多的 UI 组件,且这些 UI 组件之间存在交互关系。Fragment 简化了大屏幕 UI 的设计,它不需要开发者管理组件包含关系的复杂变化,开发者使用 Fragment 对 UI 组件进行分组、模块化管理,可以更方便地在运行过程中动态更新 Activity 的用户界面。
例如:有如下新闻浏览界面,该界面需要在屏幕左边显示新闻列表,并在屏幕右边显示新闻内容,此时就可以在 Activity 中显示两个并排的 Fragment 左边的 Fragment 显示新闻列表,右边的 Fragment 显示新闻内容。由于每个 Fragment 拥有自己的生命周期,并可响应用户输入事件,因此可以非常方便地实现:当用户单击左边列表的指定新闻时,右 Fragment 显示相应的新闻内容。下图左边的“平板电脑”部分显示了这种 Ul 界面
通过使用上面的 Fragment 设计机制,可以取代传统的让一个 Activity 显示新闻列表,一个 Activity 显示新文内容的设计。
由于 Fragment 是可复用的组件,因此如果需要在正常尺寸的手机屏幕上运行该应用,可以改为使用两个 Activity,ActivityA 包含 FragmentA、ActivityB 包含 FragmentB。其中 ActivityA 仅包含显示文章列表 FragmentA,而当用户选择一篇文章时,它会启动包含新闻内容的 ActivityB,如上图右边的“手机,部分。由此可见,Fragment 可以很好地支持上图所示的两种设计模式。
3.创建 Fragment
与创建 Activity 类似,开发者实现的 Fragment 必须继承 Fragment 基类,Android 提供了如下图所示的 Fragment 继承体系。
开发者实现的 Fragment,可以根据需要继承上图所示的 Fragment 基类或它的任意子类。接下来,实现 Fragment 与实现 Activity 非常相似,它们都需要实现与 Activity 类似的回调方法,例如 onCreate()、onCreateView()、onStart()、onResume()、onPause()、onStop() 等。
提示:
开发 Fragment 与开发 Activity 非常相似,区别只是开发 Activity 需要继承 Activity 或其子类;但开发 Fragment 需要继承 Fragment 及其子类.与此同时,只要将原来写在 Activity 回调方法的代码“移到”Fragment 的回调方法中即可。
通常来说,创建 Fragment 通常需要实现如下三个方法。
- onCreate():系统创建 Fragment 对象后回调该方法,实现代码中只初始化想要在 Fragment 中保持的必要组件,当 fragment 被暂停或者停止后可以恢复。
- onCreateView():当 Fragment 绘制界面组件时会回调该方法。该方法必须返回一个 View,该 View 也就是该 Fragment 所显示的 View。
- onPause():当用户离开该 Fragment 时将会回调该方法。
对于大部分 Fragment 而言,通常都会重写上面这三个方法。但是实际上开发者可以根据需要重写 Fragment 的任意回调方法,后面将会详细介绍 Fragment 的生命周期及其回调方法为了控制 Fragment 显示的组件,通常需要重写 onCreateView() 方法,该方法返回的 View 将作为该 Fragment 显示的 View 组件。当 Fragment 绘制界面组件时将会回调该方法。
例如如下方法片段:
// 重写该方法,该方法返回的 View 将作为 Fragment 显示的组件 @Override public View onCreateView(LayoutInflater inflater , ViewGroup container, Bundle savedInstanceState) { // 加载/res/layout/目录下的 fragment_book_detail.xml 布局文件 View rootView = inflater.inflate(R.layout. fragment_book_detail , container, false ); if ( book != null ) { // 让 book_title 文本框显示 book 对象的 title 属性 ((TextView) rootView.findViewById(R.id. book_title )) .setText( book . title ); // 让 book_desc 文本框显示 book 对象的 desc 属性 ((TextView) rootView.findViewById(R.id. book_desc )) .setText( book . desc ); } return rootView; }
实例:开发发显示图书详情的 Fragment,下面 Fragment 将会显示加载一份简单的界面布局文件,并根据传入的参数来更新界面组件该 Fragment 的代码如下。
3.1 创建 Fragment:
public class BookDetailFragment extends Fragment { public static final String ITEM_ID = "item_id" ; // 保存该 Fragment 显示的 Book 对象 BookContent.Book book ; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); // 如果启动该 Fragment 时包含了 ITEM_ID 参数 if (getArguments().containsKey( ITEM_ID )) { book = BookContent. ITEM_MAP .get(getArguments() .getInt( ITEM_ID )); //① } } // 重写该方法,该方法返回的 View 将作为 Fragment 显示的组件 @Override public View onCreateView(LayoutInflaterinflater , ViewGroup container, Bundle savedInstanceState) { // 加载/res/layout/目录下的 fragment_book_detail.xml 布局文件 View rootView =inflater.inflate(R.layout. fragment_book_detail , container, false ); if ( book != null ) { // 让 book_title 文本框显示 book 对象的 title 属性 ((TextView) rootView.findViewById(R.id. book_title )) .setText( book . title ); // 让 book_desc 文本框显示 book 对象的 desc 属性 ((TextView) rootView.findViewById(R.id. book_desc )) .setText( book . desc ); } return rootView; } }
3.2 创建 ListFragment:
public class BookDetailFragment extends Fragment { public static final String ITEM_ID = "item_id" ; // 保存该 Fragment 显示的 Book 对象 BookContent.Book book ; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); // 如果启动该 Fragment 时包含了 ITEM_ID 参数 if (getArguments().containsKey( ITEM_ID )) { book = BookContent. ITEM_MAP .get(getArguments() .getInt( ITEM_ID )); //① } } // 重写该方法,该方法返回的 View 将作为 Fragment 显示的组件 @Override public View onCreateView(LayoutInflater inflater , ViewGroup container, Bundle savedInstanceState) { // 加载/res/layout/目录下的 fragment_book_detail.xml 布局文件 View rootView = inflater.inflate(R.layout. fragment_book_detail , container, false ); if ( book != null ) { // 让 book_title 文本框显示 book 对象的 title 属性 ((TextView) rootView.findViewById(R.id. book_title )) .setText( book . title ); // 让 book_desc 文本框显示 book 对象的 desc 属性 ((TextView) rootView.findViewById(R.id. book_desc )) .setText( book . desc ); } return rootView; } }
4.Fragmemt 与 Activity 通信
为了在 activity 中显示 Fragment 还必须将 Fragment 添加到 activity 中。
4.1 将 Fragment 添加到 activity 中有如下两种方式:
1) 在布局文件中添加:在布局文件中使用元素添加 Fragment,其中的 android:name 属性必须指定 Fragment 的实现类。
2) 在 Java 代码中添加:在 Java 代码中通过 FragmentTransaction 对象的 relpace() 或 add() 方法来替换或添加 Fragment。
提示:Activity 的 getFragmentManager() 方法返回 FragmentManager,通过调用 FragmentManager 的 beginTransaction() 方法获取 FragmentTransaction 对象。
Activity 的布局文件:
<? xml version = "1.0" encoding = "utf-8" ?> <!-- 定义一个水平排列的 LinearLayout ,并指定使用中等分隔条 --> < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:orientation = "horizontal" android:layout_width = "match_parent" android:layout_height = "match_parent" android:layout_marginLeft = "16dp" android:layout_marginRight = "16dp" android:divider = "?android:attr/dividerHorizontal" android:showDividers = "middle" > <!-- 添加一个 Fragment --> < fragment android:name = "com.jph.fragmentdemo.BookListFragment" android:id = "@+id/book_list" android:layout_width = "0dp" android:layout_height = "match_parent" android:layout_weight = "1" /> <!-- 添加一个 FrameLayout 容器 --> < FrameLayout android:id = "@+id/book_detail_container" android:layout_width = "0dp" android:layout_height = "match_parent" android:layout_weight = "3" /> </ LinearLayout >
Activity 代码:
public class SelectBookActivity extends Activity implements BookListFragment.Callbacks { @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); // 加载/res/layout 目录下的 main.xml 布局文件 setContentView(R.layout. main ); } // 实现 Callbacks 接口必须实现的方法 @Override public void onItemSelected(Integer id) { // 创建 Bundle,准备向 Fragment 传入参数 Bundle arguments = new Bundle(); arguments.putInt(BookDetailFragment. ITEM_ID , id); // 创建 BookDetailFragment 对象 BookDetailFragment fragment = new BookDetailFragment(); // 向 Fragment 传入参数 fragment.setArguments(arguments); // 使用 fragment 替换 book_detail_container 容器当前显示的 Fragment getFragmentManager().beginTransaction() .replace(R.id. book_detail_container , fragment).commit(); //① } }
上而的程序中①号粗体字代码就调用了 FragmentTransaction 的 replace() 方法动态更新了 ID 为 book_detail_container 容器(也就是前面布局文件中的 FrameLayout 容器)中显示的 Fragment。
将 Fragment 添加到 Activity 之后,Fragment 必须与 Activity 交互信息,这就需要 Fragment 能获取它所在的 Activity, Activity 也能获取它所包含的任意的 Fragment。可按如下方法进行。
4.2 在 activity 中获取 Fragement,在 Fragment 中获取 activity 的方法:
1)Fragment 获取它所在的 Activity:调用 Fragment 的 getActivity() 方法即可返回它所在的 Activity。
2)Activity 获取它包含的 Fragment:调用 Activity 关联的 FragmentManager 的 findFragmentByld(int id) 或 findFragmentByTag(String tag) 方法即可获取指定的 Fragment。
提示:
在界面布局文件中使用元素添加 Fragment 时,可以为元素指定 android:id 或 android:tag 属性,这两个属性都可用于标识该 Fragment,接下来 Activity 将可通过 findFragmentByld(int id) 或 findFragmentByTag(String tag) 来获取该 Fragment。
4.3Fragment 与 Activity 可能还需要相互传递数据的方式:
1)Activity 向 Fragment 传递数据:在 Activity 中创建 Bundle 数据包,并调用 Fragment 的 setArguments(Bundle bundle) 方法即可将 Bundle 数据包传给 Fragment。
2)Fragment 向 Activity 传递数据或 Activity 需要在 Fragment 运行中进行实时通信:在 Fragment 中定义一个内部回调接口,再让包含该 Fragment 的 Activity 实现该回调接口,这样 Fragment 即可调用该回调方法将数据传给 Activity。
3) 通过广播的方式。
5.Fragment 管理与 Fragment 事务
前面介绍了 Activity 与 Fragment 交互相关的内容,其实 Activity 管理 Fragment 主要依靠 FragmentManger。
5.1FragmentMange 的功能:
1) 使用 findFragmentByld() 或 findFragmentByTag() 方法来获取指定 Fragment。
2) 调用 popBackStack() 方法将 Fragment 从后台找中弹出(模拟用户按下 BACK 按键)。
3) 调用 addOnBackStackChangeListener() 注册个监听器,用于监听后台栈的变化。如果需要添加、删除、替换 Fragment,则需要借助 FragmentTransaction 对象, FragmentTransaction 代表 Activity 对 Fragment 执行的多个改变。
提示:
FragmentTransaction 也被翻译为 Fragment 事务。与数据库事务类似的是,数据库事务代表了对底层数组的多个更新操作;而 Fragment 事务则代表了 Activity 对 Fragment 执行的多个改变操作。
每个 FragmentTransaction 可以包含多个对 Fragment 的修改,比如包含调用多个 add()、replace()、和 remove() 操作,最后调用 commit() 提交事务即可。
在调用 commit() 之前,开发者也可调用 addToBackStack() 将事务添加到 back 栈,该栈由 Activity 负责管理,这样允许用户按 BACK 按键返回到前一个 Fragment 状态。
// 创建一个新的 Fragment 并打开事务 Fragment newFragment = new ExampleFragment(); FragmentTransaction transaction = getFragmentManager().beginTransaction(); // 替换该界面中 fragment_container 容器内的 Fragment transaction.replace(R.id.fragment_container, newFragment); // 将事务添加到 back 栈,允许用户按 back 按键返回到替换 Fragment 之前的状态 transaction.addToBackStack(null); // 提交事务 transaction.commit();
在上面的示例代码中,newFragment 替换了当前界面布局中 ID 为 fragment_container 的容器内的 Fragment,由于程序调用了 addToBackStack() 将该 replace 操作添加到了 back 栈中,因此用户可以通过按下 BACK 按键返回替换之前的状态。
6.Fragment 的生命周期:
与 Activity 类似的是,Fragment 也存在如下状态。
- Ø 活动状态:当前 Fragment 位于前台,用户可见,可以获得焦点。
- Ø 暂停状态:其他 Activity 位于前台,该 Fragment 依然可见,只是不能获得焦点。
- Ø 停止状态:该 Fragment 不可见,失去焦点。
- Ø 销毁状态:该 Fragment 被完全删除,或该 Fragment 所在的 Activity 被结束。
从上图可以看出,在 Fragment 的生命周期中,如下方法会被系统回调。
- Ø onAttach():当该 Fragment 被添加到 Activity 时被回调。该方法只会被调用一次。
- Ø onCreate(Bundle savedStatus):创建 Fragment 时被回调。该方法只会被调用一次。
- Ø onCreateView():每次创建、绘制该 Fragment 的 View 组件时回调该方法,Fragment 将会显示该方法返回的 View 组件。
- Ø onActivityCreated():当 Fragment 所在的 Activity 被启动完成后回调该方法。
- Ø onStart():启动 Fragment 时被回调。
- Ø onResume():恢复 Fragment 时被回调,onStart() 方法后一定会回调()onResume() 方法。
- Ø onPause():暂停 Fragment 时被回调。
- Ø onStop():停止 Fragment 时被回调。
- Ø onDestroyView():销毁该 Fragment 所包含的 View 组件时调用。
- Ø onDestroy():销毁 Fragment 时被回调。该方法只会被调用一次。
- Ø onDetach():将该 Fragment 从 Activity 中被删除、被替换完成时回调该方法,onDestroy() 方法后一定会回调 onDetach() 方法。该方法只会被调用一次。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论