Fragment详解

一. Fragment简介

  • 我们都知道,Android上的界面展示都是通过Activity实现的,Activity实在是太常用了,我相信大家都已经非常熟悉了,这里就不再赘述。但是Activity也有它的局限性,同样的界面在手机上显示可能很好看,在平板上就未必了,因为平板的屏幕非常大,手机的界面放在平板上可能会有过分被拉长、控件间距过大等情况。这个时候更好的体验效果是在Activity中嵌入"小Activity",然后每个"小Activity"又可以拥有自己的布局。因此,我们今天的主角Fragment登场了。

  • Android在3.0版本引入了Fragment功能, Fragment根据词海的翻译可以译为:碎片、片段。Fragment不可以单独存在,是一种可以嵌入在活动当中的UI片段,它能让程序更加合理和充分地利用大屏幕,相比Activity更轻量级、更灵活。它非常类似于Activity,可以像Activity一样包含布局。Fragment通常是嵌套在Activity中使用的。
    Fragment是在3.0版本引入的,如果你使用的是3.0之前的系统,需要先导入android-support-v4的jar包才能使用Fragment功能。


二. Fragment的生命周期

  • 每一个fragments 都有自己的一套生命周期回调方法和处理自己的用户输入事件。 对应生命周期可参考下图:

1350998205_2002.png

因为Fragment必须嵌入在Acitivity中使用,所以Fragment的生命周期和它所在的Activity是密切相关的。如果Activity是暂停状态,其中所有的Fragment都是暂停状态;如果Activity是stopped状态,这个Activity中所有的Fragment都不能被启动;如果Activity被销毁,那么它其中的所有Fragment都会被销毁。但是,当Activity在活动状态,可以独立控制Fragment的状态,比如加上或者移除Fragment。

1. Fragment的几种状态

Fragment和activity一样,也是有四种状态

  • 活动状态:Resumed
    当前Fragment位于前台,用户可见,可以获得焦点;
  • 暂停状态: Paused
    另一个Activity处于前台并拥有焦点, 但是该Fragment所在的Activity仍然可见(前台Activity局部透明或者没有覆盖整个屏幕),不过不能获得焦点;
  • 停止状态:Stopped
    要么是宿主Activity已经被停止, 要么是Fragment从Activity被移除但被添加到回退栈中;停止状态的Fragment仍然活着(所有状态和成员信息被系统保持着)。 然而, 它对用户不再可见, 并且如果Activity被销毁,它也会被销毁;
  • 销毁状态:Destroyed 只能等待被回收。

2.Fragment和Activity的对比

(1)活动和碎片之间的对比图
2536652-a8cda6b9d53af55b.png
(2)由上图可以看出,Fragment比Activity多了几个额外的生命周期回调方法:
  • onAttach() 当碎片和活动建立关联时调用。(获得activity的传递的值)
  • onCreateView() 为碎片创建视图调用就是加载布局时。
  • onActivityCreated() 确保与碎片相关联的活动一定已经创建完毕的时候调用。
  • onDestroyView() 当与碎片的视图被移除的时候调用。
  • onDetach()当碎片与活动解除关联的时候调用。

三.如何使用Fragment

  • 静态使用
  1. 继承Fragment,重写onCreateView决定Fragemnt的布局
  2. 在Activity中声明此Fragment,就当和普通的View一样
    关键代码:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(layout, container, false); }

  • 动态添加
    1.创建待添加的碎片实例
    2.获取到FragmentManager,在活动中可以直接调用getFragmentManager()方法得到。
    3.开启一个事务,通过调用beginTransaction()方法开启
    4.向容器内添加碎片,一般使用replace()方法,需要传入容器的id和待添加的碎片实例。
    5.提交事务,调用commit()(方法来完成。
    关键代码:

FragmentManager fm = getFragmentManager();
// 开启Fragment事务
FragmentTransaction transaction = fm.beginTransaction();
//Fragment的布局替代控件
transaction.replace(控件的id, 碎片实例);
// 事务提交
transaction.commit();

  • 在碎片中模拟返回栈
    通过点击按钮添加了一个碎片之后,这时按下back键程序就会直接退出。如果这里我们想模仿类似返回栈的效果,按下back键可以返回到上一个碎片,在FragmentTransaction中提供了一个addToBackStack()方法,可以用于将一个事务添加到返回栈中
    关键代码:

transaction.addToBackStack(null);

注意: 在事务没有提交之前添加代码


四.Fragment的通信

Fragment和Activity之间的调用

  • 活动中调用碎片的方法:

为了方便碎片与活动之间进行通信,FragmentManager提供了一个类似于findViewById()的方法,专门从布局文件中获取碎片的实例,代码如下:

Fragment fragment=(Fragment)getFragmentManager()
.findFragmentById(R.id.fragment);

调用 FragmentManager 的 findFragmentById()方法,可以在活动中得到相应碎片的实例,这样就可以调用碎片的方法了。

  • 碎片中调用活动的方法:

在每个碎片中都可以通过调用 getActivity()方法来得到和当前碎片相关联 的活动实例,代码如下:

MainActivity activity=(MainActivity)getActivity();

获得活动实例后,就可以在碎片中调用活动的方法。另外当碎片中需要 使用 Context 对象时,也可以使用 getActivity()方法,因为获取到的活动本身就是一个Context对象了。

Fragment和Activity之间的通信

  • ** Handler方案**
public class MainActivity extends FragmentActivity{ //声明一个Handler  public Handler mHandler = new Handler(){ 
@Override 
public void handleMessage(Message msg) { 
super.handleMessage(msg);
 ...相应的处理代码
 }
 }
 ...相应的处理代码 
}
 public class MainFragment extends Fragment{
 //保存Activity传递的handler
 private Handler mHandler; 
@Override
 public void onAttach(Activity activity) { 
super.onAttach(activity);
 //这个地方已经产生了耦合,若还有其他的activity,这个地方就得修改 
 if(activity instance MainActivity){ 
mHandler = ((MainActivity)activity).mHandler;
 }
 }
 ...相应的处理代码
 }

该方案存在的缺点:
Fragment对具体的Activity存在耦合,不利于Fragment复用
不利于维护,若想删除相应的Activity,Fragment也得改动
没法获取Activity的返回数据

  • EventBus方案
    主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息.优点是开销小,代码更优雅。以及将发送者和接收者解耦。
    1、下载EventBus的类库源码:https://github.com/greenrobot/EventBus
    2、基本使用
    (1)自定义一个类,可以是空类,比如:
public class AnyEventType {  
     public AnyEventType(){}  
 }  

(2)在要接收消息的页面注册:

eventBus.register(this);  

(3)发送消息

eventBus.post(new AnyEventType event);  

(4)接受消息的页面实现(共有四个函数,各功能不同,这是其中之一,可以选择性的实现,这里先实现一个):

public void onEvent(AnyEventType event) {}  

(5)解除注册

eventBus.unregister(this); 

注意:在EventBus中,获取实例的方法一般是采用EventBus.getInstance()来获取默认的EventBus实例,当然你也可以new一个实例。

  • setArguments(Bundle bundle)方案:
 public class ExampleFragment extends Fragment{
 private String type; 
public static ExampleFragment newInstance(String type) { 
ExampleFragment myFragment = new ExampleFragment(); 
Bundle args = new Bundle(); 
args.putString("type", type);
//发送要传递的值
myFragment.setArguments(args);
return myFragment; 
} 
@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
//接收数据
type=getArguments().getString("type");
 ...相应的处理代码
 }
}

这种activity向fragment传值方法是最简单有效的,而且在fragment异常重建的时候bundle将参数保存了下来

  • ** 使用接口回调的方法通信(推荐)**
//MainActivity 实现MainFragment的接口
public class MainActivity extends FragmentActivity implements FragmentListener{ 
@override
 public void toInterface (){ } ...其他处理代码省略 }
public class MainFragment extends Fragment{ 
public FragmentListener mListener;
 //MainFragment开放的接口 
public static interface FragmentListener{ 
void toInterface (); }
 @Override 
public void onAttach(Activity activity) {
 super.onAttach(activity); 
//对传递进来的Activity进行接口转换 
if(activity instance FragmentListener){ 
mListener = ((FragmentListener)activity);
 } } ...其他处理代码省略 }

这种方案应该是既能达到复用,又能达到很好的可维护性,并且性能很好(推荐使用)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容