Fragment详解(1)

一、Fragmeng优点

  • Fragment可以使你能够将activity分离成多个可重用的组件,每个都有它自己的生命周期和UI。
  • Fragment可以轻松得创建动态灵活的UI设计,可以适应于不同的屏幕尺寸。从手机到平板电脑。
  • Fragment是一个独立的模块,紧紧地与activity绑定在一起。可以运行中动态地移除、加入、交换等。
  • Fragment提供一个新的方式让你在不同的安卓设备上统一你的UI。
  • Fragment 解决Activity间的切换不流畅,轻量切换。
  • Fragment 替代TabActivity做导航,性能更好。
  • Fragment 在4.2.版本中新增嵌套fragmeng使用方法,能够生成更好的界面效果。
  • Fragment做局部内容更新更方便,原来为了到达这一点要把多个布局放到一个activity里面,现在可以用多Fragment来代替,只有在需要的时候才加载Fragment,提高性能

  • 二、生命周期

  • 如图一,是Fragment的生命周期;图二,是Activity与Fragment生命周期的对比图; 
                                               图一                                                                 图二 

     

    我们下面以Fragment的生命流程为主,伴着Activity的生命周期来讲;

    • onAttach:onAttach()在fragment与Activity关联之后调调查用。需要注意的是,初始化fragment参数可以从getArguments()获得,但是,当Fragment附加到Activity之后,就无法再调用setArguments()。所以除了在最开始时,其它时间都无法向初始化参数添加内容。有关Fragment参数初始化及传递的问题,我们会在后面的篇章中细讲。
      • onCreate:fragment初次创建时调用。尽管它看起来像是Activity的OnCreate()函数,但这个只是用来创建Fragment的。此时的Activity还没有创建完成,因为我们的Fragment也是Activity创建的一部分。所以如果你想在这里使用Activity中的一些资源,将会获取不到。比如:获取同一个Activity中其它Frament的控件实例。(代码如下:),如果想要获得Activity相关联的资源,必须在onActivityCreated中获取。
      具体原因参见onActivityCreated;

      [java]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. /** 
      2. *如果把这段代码放到Fragment的onCreate()中,那么btnTry的值将会是NULL。 
      3. *注意:getActivity()是有值的,因为一旦Activity与Fragment Attached就可以通过getActivity()来获取相关联的Activity的实例。 
      4. */  
      5. Button btnTry = getActivity().findViewById(R.id.btn_try);  
      • onCreateView:在这个fragment构造它的用户接口视图(即布局)时调用。在这里期望返回此Fragment的一个视图层次结构。使用LayoutInflater的inflater()方法来构造实图。代码如下:
      [java]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. public View onCreateView(LayoutInflater inflater, ViewGroup container,  
      2.                          Bundle savedInstanceState) {  
      3.     return inflater.inflate(R.layout.fragment3, container, false);  
      4. }  

      其中LayoutInflater::inflate()的函数声明如下:

      [java]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. public View inflate(int resource, ViewGroup root, boolean attachToRoot)  

      其中第二个参数:Container,可以为NULL,如果父窗口值为NULL,这意味着该Fragment不可见,因为它没有附加到任何的视图层次中。

      最后一个参数:boolean attachToRoot:一般为FALSE,它的意义为,是否当前XML的根结点作为整个APP视图的根结点,如果设为TRUE,那返回的VIEW将是整个APP视图架构的根结点,我们一般不需要这么做。因为我们的Fragment是依附于Activity的,Activity上可能有其它控件,我们的Fragment只是其中的一个小分支,如果这里设为TRUE,那么Fragment以外的分支将被全部删除,整个APP视图将会只有Fragment;
      • onActivityCreated:在Activity的OnCreate()结束后,会调用此方法。所以到这里的时候,Activity已经创建完成!在这个函数中才可以使用Activity的所有资源。如果把下面的代码放在这里,获取到的btn_Try的值将不会再是空的!

      [java]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. Button btnTry = getActivity().findViewById(R.id.btn_try);  
      • onStart:当到OnStart()时,Fragment对用户就是可见的了。但用户还未开始与Fragment交互。在生命周期中也可以看到Fragment的OnStart()过程与Activity的OnStart()过程是绑定的。意义即是一样的。以前你写在Activity的OnStart()中来处理的代码,用Fragment来实现时,依然可以放在OnStart()中来处理。
      • onResume:当这个fragment对用户可见并且正在运行时调用。这是Fragment与用户交互之前的最后一个回调。从生命周期对比中,可以看到,Fragment的OnResume与Activity的OnResume是相互绑定的,意义是一样的。它依赖于包含它的activity的Activity.onResume。当OnResume()结束后,就可以正式与用户交互了。
      • onPause:此回调与Activity的OnPause()相绑定,与Activity的OnPause()意义一样。
      • onStop:这个回调与Activity的OnStop()相绑定,意义一样。已停止的Fragment可以直接返回到OnStart()回调,然后调用OnResume()。
      • onDestroyView:如果Fragment即将被结束或保存,那么撤销方向上的下一个回调将是onDestoryView()。会将在onCreateView创建的视图与这个fragment分离。下次这个fragment若要显示,那么将会创建新视图。这会在onStop之后和onDestroy之前调用。这个方法的调用同onCreateView是否返回非null视图无关。它会潜在的在这个视图状态被保存之后以及它被它的父视图回收之前调用。
      • onDestroy:当这个fragment不再使用时调用。需要注意的是,它即使经过了onDestroy()阶段,但仍然能从Activity中找到,因为它还没有Detach。
      • onDetach:Fragment生命周期中最后一个回调是onDetach()。调用它以后,Fragment就不再与Activity相绑定,它也不再拥有视图层次结构,它的所有资源都将被释放。

      三丶静态添加Fragment

      新建一个项目harvicBlog2Static,在其中添加一个布局:fragment1.xml:

      [html]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    
      2.     android:layout_width="match_parent"    
      3.     android:layout_height="match_parent"    
      4.     android:background="#00ff00" >    
      5.     
      6.     <TextView    
      7.         android:layout_width="wrap_content"    
      8.         android:layout_height="wrap_content"    
      9.         android:text="This is fragment 1"    
      10.         android:textColor="#000000"    
      11.         android:textSize="25sp" />    
      12.     
      13. </LinearLayout>    
      可以看到,这个布局文件非常简单,只有一个LinearLayout,里面加入了一个TextView。我们如法炮制再新建一个fragment2.xml :
      [html]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
      2.     android:layout_width="match_parent"  
      3.     android:layout_height="match_parent"  
      4.     android:background="#ffff00" >  
      5.   
      6.     <TextView  
      7.         android:layout_width="wrap_content"  
      8.         android:layout_height="wrap_content"  
      9.         android:text="This is fragment 2"  
      10.         android:textColor="#000000"  
      11.         android:textSize="25sp" />  
      12.   
      13. </LinearLayout>  
      然后新建一个类Fragment1,这个类是继承自Fragment的:
      [java]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. import android.os.Bundle;  
      2. import android.support.v4.app.Fragment;  
      3. import android.view.LayoutInflater;  
      4. import android.view.View;  
      5. import android.view.ViewGroup;  
      6.   
      7. /** 
      8.  * Created by harvic on 2015/4/5. 
      9.  */  
      10. public class Fragment1 extends Fragment {  
      11.     @Override  
      12.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
      13.         return inflater.inflate(R.layout.fragment1, container, false);  
      14.     }  
      15. }  
      注意,使用的V4包中的Fragment!这里的代码主要就是加载了我们刚刚写好的fragment1.xml布局文件并返回。同样的方法,我们再写好Fragment2 :
      [java]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. import android.os.Bundle;  
      2. import android.support.v4.app.Fragment;  
      3. import android.view.LayoutInflater;  
      4. import android.view.View;  
      5. import android.view.ViewGroup;  
      6.   
      7. /** 
      8.  * Created by harvic on 2015/4/5. 
      9.  */  
      10. public class Fragment2 extends Fragment {  
      11.     @Override  
      12.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
      13.         return inflater.inflate(R.layout.fragment2, container, false);  
      14.     }  
      15. }  
      然后打开或新建activity_main.xml作为主Activity的布局文件,在里面加入两个Fragment的引用,使用android:name前缀来引用具体的Fragment:
      [java]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
      2.     android:layout_width="match_parent"  
      3.     android:layout_height="match_parent"  
      4.     android:baselineAligned="false" >  
      5.   
      6.     <fragment  
      7.         android:id="@+id/fragment1"  
      8.         android:name="com.harvic.com.harvicblog2.Fragment1"  
      9.         android:layout_width="0dip"  
      10.         android:layout_height="match_parent"  
      11.         android:layout_weight="1" />  
      12.   
      13.     <fragment  
      14.         android:id="@+id/fragment2"  
      15.         android:name="com.harvic.com.harvicblog2.Fragment2"  
      16.         android:layout_width="0dip"  
      17.         android:layout_height="match_parent"  
      18.         android:layout_weight="1" />  
      19.   
      20. </LinearLayout>  
      至于MainActivity,由于我们使用的V4包,必须将MainActivity派生自FragmentActivity,否则根本无法启动程序!因为系统的Activity只能用来盛装系统自带的Fragment,而无法盛装V4包中的Fragment,因为系统的Activity根本无法识别V4包中的Fragment,因为这根本就不是一块的代码!如果不使用V4包,使用系统自带的Fragment则不必将MainActivity派生自FragmentActivity。
      [java]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. import android.os.Bundle;  
      2. import android.support.v4.app.FragmentActivity;  
      3.   
      4. public class MainActivity extends FragmentActivity {  
      5.   
      6.     @Override  
      7.     protected void onCreate(Bundle savedInstanceState) {  
      8.         super.onCreate(savedInstanceState);  
      9.         setContentView(R.layout.activity_main);  
      10.     }  
      11. }  
      效果图如下:

      源码在文章最底部给出

      二、动态添加Fragment

      你已经学会了如何在XML中使用Fragment,但是这仅仅是Fragment最简单的功能而已。Fragment真正的强大之处在于可以动态地添加到Activity当中,因此这也是你必须要掌握的东西。当你学会了在程序运行时向Activity添加Fragment,程序的界面就可以定制的更加多样化。下面我们立刻来看看,如何动态添加Fragment。

      还是在上一节代码的基础上修改,打开activity_main.xml,将其中代码全部删除,改成下面的样子:

      [html]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
      2.     android:layout_width="match_parent"  
      3.     android:layout_height="match_parent"  
      4.     android:orientation="vertical"  
      5.     android:baselineAligned="false" >  
      6.   
      7.     <Button  
      8.         android:id="@+id/btn_show_fragment1"  
      9.         android:layout_width="match_parent"  
      10.         android:layout_height="wrap_content"  
      11.         android:text="显示Fragment1"/>  
      12.   
      13.     <Button  
      14.         android:id="@+id/btn_show_fragment2"  
      15.         android:layout_width="match_parent"  
      16.         android:layout_height="wrap_content"  
      17.         android:text="显示Fragment2"/>  
      18.   
      19.     <FrameLayout  
      20.         android:id="@+id/fragment_container"  
      21.         android:layout_width="match_parent"  
      22.         android:layout_height="match_parent"/>  
      23.   
      24. </LinearLayout>  
      主界面上有两个按钮和一个FrameLayout布局。这两个按钮分别用来在这个FrameLayout加载Fragment1和Fragment2的实例。效果如下:
      (由于在录GIF时,绿色会出问题,所以把fragment1的背景改成了紫色)

      其它代码都没有动,主要的是在MainActivity里,点击这两个按钮时做的处理:

      [java]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. public class MainActivity extends FragmentActivity {  
      2.   
      3.     @Override  
      4.     protected void onCreate(Bundle savedInstanceState) {  
      5.         super.onCreate(savedInstanceState);  
      6.         setContentView(R.layout.activity_main);  
      7.   
      8.         Button btnLoadFrag1 = (Button)findViewById(R.id.btn_show_fragment1);  
      9.         btnLoadFrag1.setOnClickListener(new View.OnClickListener() {  
      10.             @Override  
      11.             public void onClick(View v) {  
      12.                 FragmentManager manager = getSupportFragmentManager();  
      13.                 FragmentTransaction transaction = manager.beginTransaction();  
      14.                 Fragment1 fragment1 = new Fragment1();  
      15.                 transaction.add(R.id.fragment_container, fragment1);  
      16.                 transaction.commit();  
      17.             }  
      18.         });  
      19.   
      20.         Button btnLoagFrag2 = (Button)findViewById(R.id.btn_show_fragment2);  
      21.         btnLoagFrag2.setOnClickListener(new View.OnClickListener() {  
      22.             @Override  
      23.             public void onClick(View v) {  
      24.                 FragmentManager manager = getSupportFragmentManager();  
      25.                 FragmentTransaction transaction = manager.beginTransaction();  
      26.                 Fragment2 fragment2 = new Fragment2();  
      27.                 transaction.add(R.id.fragment_container, fragment2);  
      28.                 transaction.commit();  
      29.             }  
      30.         });  
      31.     }  
      32. }  
      看上面的代码很容易明白,在点击按钮时都做了类似的操作:
      [java]  view plain  copy
        在CODE上查看代码片 派生到我的代码片
      1. FragmentManager manager = getSupportFragmentManager();  
      2. FragmentTransaction transaction = manager.beginTransaction();  
      3. Fragment1 fragment1 = new Fragment1();  
      4. transaction.add(R.id.fragment_container, fragment1);  
      5. transaction.commit();  
      动态添加Fragment主要分为4步:
      • 1.获取到FragmentManager,在V4包中通过getSupportFragmentManager,在系统中原生的Fragment是通过getFragmentManager获得的。
      • 2.开启一个事务,通过调用beginTransaction方法开启。
      • 3.向容器内加入Fragment,一般使用add或者replace方法实现,需要传入容器的id和Fragment的实例。
      • 4.提交事务,调用commit方法提交。 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值