Fragment详

作者: alsheng | 来源:发表于2016-08-02 11:29 被阅读0次

    一. 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);
     } } ...其他处理代码省略 }
    

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

    相关文章

      网友评论

        本文标题: Fragment详

        本文链接:https://www.haomeiwen.com/subject/dwoxsttx.html