您的位置:首页 > 移动开发 > Android开发

Android 开发 之 Fragment 详解

2015-07-22 17:54 696 查看
转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/38064191
本博客代码地址 :

-- 单一 Fragment 示例 : https://github.com/han1202012/Octopus-Fragement.git
-- 可复用的 Fragment 示例 : https://github.com/han1202012/Octopus-Fragement_TwoModel.git

1. Fragement 概述

Fragement 与 Activity 生命周期关系 : Fragement 嵌入到 Activity 组件中才可以使用, 其生命周期与 Activity 生命周期相关.

-- stop 与 destroy 状态 : Activity 暂停 或者 销毁的时候, 其内部嵌入的所有的
Fragement 也会执行 暂停 或者 销毁
操作;

-- 活动状态 : 只有当 Activity 处于活动状态的时候, 我们才能操作 Fragement;

Fragement 特征 :

-- Fragement 与 Activity 交互 : Fragement 调用 getActivity() 获取其 所嵌入的 Activity, Activity 获取
FragementManager 的findFragementById() 或 findFragementByTag() 获取 Fragement;

-- Activity 增删 Fragement : Activity 调用 Fragement 的 add(),
remove(), replace() 等方法 添加 删除 替换 Fragement;

-- Fragement 与 Activity 对应关系 : 一个 Activity 中可以嵌入多个 Fragement, 一个 Fragement 可以嵌入多个 Activity;

-- 生命周期受 Activity 影响 : Fragement 的生命周期 受 Activity 生命周期控制;

Fragement 作用 : Fragement 是为了 Android 中 平台电脑 UI 设计, 开发者不用设计 非常负责的 界面, 只需要设计好模块, 对UI 组件进行
分组模块化的设计和开发, 简化了 UI 组件;

Fragement 可复用性 : 同一个 app 应用, 可以在不同的 Activity 中加载同一个 Fragement;

2. Fragement 类 和 方法介绍

(1) Fragement 相关类介绍

Fragement 子类 :

-- DialogFragement : 对话框界面的 Fragement, 显示一个浮动的对话框, 这个对话框可以方便的与 Activity 进行交互, Activity 可以管理这个 Fragment;

-- ListFragement : 列表界面的 Fragement, 显示一个条目列表, 该列表可以设置一个适配器, 提供了许多管理 列表的函数;

-- PerformanceFragement : 选项设置界面的 Fragement, 该Fragment 创建 类似与 设置 应用程序时很管用;

-- WebViewFragement : WebView 界面的 Fragement;

(2) Fragement 生命周期相关方法介绍

onCreate() :

?
-- 回调时机 : 在创建 Fragement 的时候回调;

-- 参数解析 : Bundle savedInstance, 用于保存 Fragment 参数, Fragement 也可以 重写 onSaveInstanceState(Bundle outState) 方法, 保存Fragement状态;

-- 执行的动作 : 获取 Frgement 显示的内容, 以及启动Fragment 传入的参数, 调用 getArguments() 获取键值对;

onCreateView() :

?
-- 回调时机 : Fragement 绘制界面组件 的时候回调, 该方法返回 View, 这个View就是 Fragement 本身;

-- 参数解析 : inflater 布局加载器, 是上下文传入, 不用自己创建; container 加载组件的父容器;

-- 执行的操作 : 使用 inflate 布局加载器 加载布局文件, 并未组件设置显示的值;

onPause() :

-- 回调时机 : Fragement 暂停的时候, 即进入后台的时候 回调;

3. Fragment 创建

Fragment 创建 :

-- 参数准备 : 创建一个 Bundle 对象, 并向其中设置参数 :

?
-- 创建 Fragment 对象 : 使用 new MyFragment() 创建对象, 并 调用 myFragment.setArguments(bundle) 方法传入参数;

?
Fragment嵌入Activity方式 : Fragment 添加到 Activity 中才能显示, 以下是将 Fragment 嵌入 Activity 的方式;

-- 布局文件嵌入 : 在布局文件中 使用 元素, 通过定义 android:name = "com.example.MyFragment" 属性指定 Fragment 类;

-- 代码方式嵌入 : 调用 FragmentTransaction 对象的 add() 方法向 Activity 中添加 Fragment;

4. Fragment 与 Activity 通信

Fragment 获取 Activity : 调用 Fragment 对象的 getActivity()方法, 即可获取 Fragment 嵌入的 Activity 对象;

Activity 获取 Fragment :

-- Fragment 属性 : 在布局文件中, 可以为 元素指定 android:id 和 android:tag 属性;

-- 获取方法 : 调用 Activity 的 findFragmentById(int id) 或者 findFragmentByTag(String tag)方法;

Fragment 向 Activity 传递数据 : 将 Activity 当作接口子类对象, Fragment 中调用 Activity 中的接口方法;

-- Fragment 定义接口 : 在 Fragment 内部定义一个 Callback 接口;

-- Activity 实现该接口 : MyActivity extends Activity implement MyFragment.Callback;

-- Fragment 中获取该接口对象 : 在Fragment 中定义一个 Callback 全局变量, 然后在 onAttach(Activity activity) 方法中, 将
activity 强转为 Callback 对象;

-- 调用接口方法 : 上面获取了 Callback 对象, 即Activity对象, 调用 Activity 中的
接口方法
, 就能在 Fragment 中调用 Activity 对应的方法了;

Activity 向 Fragment 传递数据 :

-- 创建 Bundle 数据包 : 创建一个 Bundle 对象, 把要存放的键值对 放到这个对象中;

-- 设置 Bundle 对象给 Fragment : 调用 Fragment 对象的 setArguments(Bundle bundle) 方法, 将 Bundle 对象设置给 Fragment;

5. Fragment 事务管理

FragmentManager 功能 : FragmentManager 对象 可以通过 activity.getFragmentManager()获取;

-- 获取指定 Fragment : 通过 findFragmentById() 或者 findFragmentByTag() 方法获取指定 Fragment;

-- 弹出栈 : 通过调用 popBackStack(), 将 Fragment 从后台的 栈 中弹出;

-- 监听栈 : 通过调用 addOnBackStackChangeListener 注册监听器, 监听 后台栈变化;

FragmentTransaction 对象获取途径 :

-- 获取 FragmentManager 对象 : 调用 Activity 的 getFragmentManager() 获取 FragmentManager 对象;

-- 获取 FragmentTansaction 对象 : 调用 FragmentManager 对象的
beginTransaction()
方法获取 FragmentTransaction 对象;

FragmentTransaction(Fragment 事务)作用 : 对 Fragement 进行 增, 删 , 改 操作需要 FragmentTransaction 对象进行操作, 开启 这个事务, 获取 事务对象, 然后执行对 Fragment 的操作, 最后提交事务;

-- 开启事务 : 调用 Fragement 对象的 beginTransaction()
方法可以获取 FragementTransaction 对象;

-- 操作碎片 : FragmentTransaction 对象 中 包含了 add(), remove(), replace() 等方法;

-- 提交操作 : 当执行完 Fragement 的操作之后, 可以调用 FragementTransaction 对象的
commit() 方法提交修改;

addToBackStack()方法作用 : 该方法是 FragementTransaction 的方法, 在提交事务前调用该方法, 可以将 事务中执行的操作 添加到 back 栈中, 用户按下 回退键,
修改过的 Fragement 会 回退到 事务执行之前的状态;

6. Fragment 生命周期

(1) Fragment 状态

活动状态 : Fragment 处于前台, 可见, 可以获取焦点;

暂停状态 : Fragment 嵌入的Activity 也处于暂停状态, 即 Fragment 处于后台,
可见
, 失去焦点;

停止状态 : Fragement 嵌入的 Activity 处于停止状态, 不可见,
失去焦点
;

销毁状态 : Fragement 所在的 Activity 被销毁, 执行了 onDestroy() 方法, 此时 Fragement 被完全删除;

(2) Fragement 生命周期相关方法



红色方法 与 Activity 相对应, 蓝色方法 是 自身对应的方法,
棕色方法
单独对应;<喎�"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD48cD48YnIgLz48L3A+PHA+PHN0cm9uZz5vbkF0dGFjaCgpPC9zdHJvbmc+IDogx7bI6ywgRnJhZ2VtZW50ILG7x7bI67W9IEFjdGl2aXR5IMqxu9i197jDt723qCwg1ru74bX308PSu7TOOzwvcD48cD48YnIgLz48L3A+PHA+PHN0cm9uZz5vbkNyZWF0ZSgpIDwvc3Ryb25nPjogtLS9qCwgRnJhZ2VtZW50ILS0vai1xMqxuvK72LX3uMO3vbeoLCDWu7vhu9i199K7tM47PC9wPjxwPjxiciAvPjwvcD48cD48c3Ryb25nPm9uQ3JlYXRlVmlldygpIDwvc3Ryb25nPjogu+bWxiwg1NogRnJhZ2VtZW50ILvm1sa1xMqxuvK72LX3uMO3vbeoLCC4w7e9t6i74be1u9ggu+bWxrXEIFZpZXcg1+m8/js8L3A+PHA+PGJyIC8+PC9wPjxwPjxzdHJvbmc+b25BY3Rpdml0eUNyZWF0ZWQoKTwvc3Ryb25nPiA6IL3nw+a0tL2oLCBGcmFnZW1lbnQgy/nHtsjrtcQgQWN0aXZpdHkgtLS9qM3qs8m72LX3uMO3vbeoOzwvcD48cD48YnIgLz48L3A+PHA+PHN0cm9uZz5vblN0YXJ0KCkgPC9zdHJvbmc+OiDG9LavLCBGcmFnZW1lbnQgxvS2r8qxu9i19ywgtMvKsUZyYWdlbWVudL/JvPs7PC9wPjxwPjxiciAvPjwvcD48cD48c3Ryb25nPm9uUmVzdW1lKCk8L3N0cm9uZz4gOiC8pLvuLCBGcmFnZW1lbnQgvfjI68ewzKgsIL/Ju/HIob25tePKsbyku+47PC9wPjxwPjxiciAvPjwvcD48cD48c3Ryb25nPm9uUGF1c2UoKTwvc3Ryb25nPiA6INTdzaMsIEZyYWdlbWVudCC9+MjruvPMqCwgsru/ybvxyKG9ubXjyrG8pLvuOzwvcD48cD48YnIgLz48L3A+PHA+PHN0cm9uZz5vblN0b3AoKTwvc3Ryb25nPiA6IM2j1rksIEZyYWdlbWVudCCyu7/JvPvKsbvYtfc7PC9wPjxwPjxiciAvPjwvcD48cD48c3Ryb25nPm9uRGVzdHJveVZpZXcoKTwvc3Ryb25nPiA6IM/6u9nX6bz+LCDP+rvZIEZyYWdlbWVudCC75tbGtcQgVmlldyDX6bz+yrG72LX3OzwvcD48cD48YnIgLz48L3A+PHA+PHN0cm9uZz5vbkRlc3Ryb3koKTwvc3Ryb25nPiA6IM/6u9ksIM/6u9kgRnJhZ2VtZW50ILvYtfc7PC9wPjxwPjxiciAvPjwvcD48cD48c3Ryb25nPm9uRGV0YWNoKCk8L3N0cm9uZz4gOiDSxrP9LCBGcmFnZW1lbnQgtNMgQWN0aXZpdHkg1tDSxrP9tcTKsbryu9i19zs8L3A+PHA+PGJyIC8+PC9wPjxwPjxiciAvPjwvcD48aDI+Ny4gtPrC68q+wP0gPC9oMj48cD48YnIgLz48L3A+PHA+PGJyIC8+PC9wPjxoMz4oMSkg0OjH87fWzvY8L2gzPjxwPjxiciAvPjwvcD48cD48c3Ryb25nPtfdz/LK1rv6xsHEuzwvc3Ryb25nPiA6IMG9uPa958PmLCDDv7j2vefD5ra809DSu7j2IEZyYWdlbWVudCwgINK7uPZGcmFnZW1lbnTP1Mq+0MLOxcHQse0sINK7uPZGcmFnZW1lbnQgz9TKvtDCzsXE2sjdOzwvcD48cD48c3Ryb25nPrrhz/LK1rv6xsHEuzwvc3Ryb25nPiA6INK7uPa958PmLCDBvbj2RnJhZ2VtZW50LCBGcmFnZW1lbnQgz9TKvsTayN3T68nPw+bP4M2sOzwvcD48cD48YnIgLz48L3A+PHA+PGJyIC8+PC9wPjxoMz4oMikg0MLOxbHqzOIgRnJhZ21lbnQ8L2gzPjxwPjxiciAvPjwvcD48cD48c3Ryb25nPrTmt8XQws7FserM4rXEIEZyYWdtZW50PC9zdHJvbmc+IDogTmV3c1RpdHRsZUZyYWdtZW50LmphdmE8L3A+PHA+PC9wPjxwcmUgY2xhc3M9"brush:java;">package
cn.org.octopus;import android.app.Activity;import android.app.ListFragment;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ArrayAdapter;import android.widget.ListAdapter;import
android.widget.ListView;/** * 内部类 : * Callbacks接口 * Fragement中维护该接口子类对象 * 需要Activity实现该接口, 实现接口方法 * Activity 在onAttach()方法中传入; * * 方法简介 : * 重写生命周期的 11 个方法; * onAttach() 方法中, 传入所嵌入的Activity, 并判断是否嵌入正确 * onCreate() 方法中, 创建 Fragement 中 ListView 的适配器, 并将适配器设置给
ListView * onDetach() 方法中, 将 Callbacks 接口子类对象置空 * * setChoiceMode() 设置ListView 的选择模式 * onListItemClick() ListView 的点击回调方法 * 注意 Android * */public class NewsTittleFragment extends ListFragment {private Callbacks activityCallback; /* 从 onAttach()方法中传入的 Callbacks
接口子类, 由 Activity 强制转换而来 *//** 定义回调接口 * 接口用法 : * 1. 该 Fragement 所 Activity 实现该接口 * 2. 该 Fragement 中 维护一个 该接口子类, 即 Activity * 3. 调用 Activity 接口子类的方法, 将数据传递给 Activity **/public interface Callbacks{public void onNewsSelect(int id);}/** Fragment 嵌入Activity */@Overridepublic
void onAttach(Activity activity) {super.onAttach(activity);System.out.println("onAttach");if ( ! ( activity instanceof Callbacks))System.out.println("Fragement in wrong Activity !");/* 为Activity中定义的Callbacks接口子类对象赋值 */activityCallback = (Callbacks) activity;}/**
Fragement 创建 * 进行设置适配器操作 */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);System.out.println("onCreate");/* 为 ListFragment 创建适配器 * 注意使用的是 Android 自带的布局, 在 sdk\platforms\android-10\data\res\layout 目录下 * */ListAdapter
adapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_activated_1, android.R.id.text1, NewsContent.getInstance().news);/* 设置适配器 给 ListFragement */setListAdapter(adapter);}/** Fragment 绘制 */@Overridepublic View onCreateView(LayoutInflater
inflater, ViewGroup container,Bundle savedInstanceState) {System.out.println("onCreateView");return super.onCreateView(inflater, container, savedInstanceState);}/** Activity 创建完毕 */@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);System.out.println("onActivityCreated");}/**
Fragement 进入可视状态 */@Overridepublic void onStart() {super.onStart();System.out.println("onStart");}/** Fragement 进入激活状态 */@Overridepublic void onResume() {super.onResume();System.out.println("onResume");}/** Fragement 进入暂停状态 */@Overridepublic void onPause()
{super.onPause();System.out.println("onPause");}/** Fragement 进入停止状态 */@Overridepublic void onStop() {super.onStop();System.out.println("onStop");}/** 销毁 Fragement 显示组件 */@Overridepublic void onDestroyView() {super.onDestroyView();System.out.println("onDestroyView");}/**
销毁 Fragement */@Overridepublic void onDestroy() {super.onDestroy();System.out.println("onDestroy");}/** 将 Fragement 从 Activity 中删除 */@Overridepublic void onDetach() {super.onDetach();System.out.println("onDetach");activityCallback = null;}/** * 列表对象被点击之后回调的方法
*/@Overridepublic void onListItemClick(ListView l, View v, int position, long id) {super.onListItemClick(l, v, position, id);activityCallback.onNewsSelect((int) id);}/** 设定选择模式, 该列表默认不能选择, 可以设置为不能选择, 单选 和 多选 * ListView.CHOICE_MODE_NONE 不能选择 * ListView.CHOICE_MODE_SINGLE
单选 * ListView.CHOICE_MODE_MULTIPLE 多选 * */public void setChoiceMode(int choiceMode) {getListView().setChoiceMode(choiceMode);}}

(3) 新闻内容的 Fragment

存放新闻内容的 Fragment : NewsContentFragement.java;

?

(4) 新闻内容存储相关代码

新闻实体类 :

?
新闻数据 :

?

(5) 主界面 Actiity 代码

主界面代码 : MainActivity.java

?

(6) AndroidManifest.xml 配置文件

?

(7) 执行结果

跟踪的 Fragment 生命周期回调函数打印的结果 :

?
界面执行结果 :



.

8. 出错处理

(1) 引用 不用包中的 Fragment

引用 android.app.ListFragment, 不会出现错误, 而 引用 android.support.v4.app.ListFragment 类会出现如下错误;

错误 :

?

(2) ListView 适配器设置错误

ListView 适配器引用的 组件, 必须是已经加载过的, 通过 onCreate()中的 setContentView()方法加载, 或者通过 LayoutInflater 进行加载;

错误 :

?

9. Fragement 复用问题

需求 : 在手机竖屏的时候, 新闻列表 和 新闻内容 在两个 Activity 中, 横屏的时候, 在一个 Activity 中;

(1) 根据不同的环境加载不同的布局

定义实际引用的资源 : 在
Java 代码中引用资源的时候, 会到 values 中查询, 是否有定义资源文件, 如果有, 优先按照该定义加载指定资源文件;

-- 定义方式 : 下面的定义, 如果代码中引用 R.layout.activity_main, 符合条件的话, 使用 R.layout.activity_main_land 布局文件;

?
-- 属性说明 : type 资源的类型, name 资源名称;

(2) 判断加载的布局文件

判断的依据 : 根据 两个布局文件的差异, 任意查找一个组件, 或者定义一个 不占位置的组件, 来进行判定;

?

(3) MainActivity 代码差异

?

(4) 新增了 NewsContentActivity

?

(5) 新增 或 修改的布局文件

activity_main.xml :

?
activity_main_land.xml :

?
activity_news_content.xml :

?

(6) 执行效果

竖屏 :



横屏 :



作者 : 韩曙亮

转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/380641
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: