Fragment应用之简述

Fragment的应用真的是越来越广泛了,之前Android在3.0版本加入Fragment的时候,主要是为了解决Android Pad屏幕比较大,空间不能充分利用的问题。但随着界面布局的复杂化,处理起来也更加的复杂,引入Fragment可以把activity拆分成各个部分。每个Fragment都有它自己的布局和生命周期。

一、Fragment的生命周期

Fragment应用之简述_第1张图片
Fragment生命周期.png
  1. onAttach()
    作用:fragment已经关联到activity。
@Override
  public void onAttach(Activity activity) {
      super.onAttach(activity);
      Log.i("onAttach_Fragment");
  }

该方法有一个Activity类型的参数,代表绑定的Activity,获得activity的传递的值 就可以进行 与activity的通信里, 当然也可以使用getActivity(),前提是这个fragment已经和宿主的activity关联,并且没有脱离。

  1. **onCreate() **
    作用:初始化Fragment,系统创建fragment的时候回调该方法,在该方法里面实例化一些变量,参数是:Bundle savedInstance, 用于保存 Fragment 参数, Fragement 也可以重写 onSaveInstanceState(BundleoutState) 方法, 保存Fragement状态。
  2. onCreateView()
    作用:初始化Fragment的布局。加载布局和findViewById的操作通常在此函数内完成,当系统用到fragment的时候 fragment就要返回它的view,越快越好 ,所以尽量在这里不要做耗时操作,比如从数据库加载大量数据,可进行各种判断省得每次都要加载,减少资源消耗,实例如下:
if(text==null){
      Bundle args=getArguments();
      text=args.getString("text");
    }
    if (view == null) {
      view = inflater.inflate(R.layout.hello, null);
    }
  1. onActivityCreated()
    作用:初始化那些你需要你的父Activity或者Fragment的UI已经被完整初始化才能初始化的元素。
    执行该方法时,与Fragment绑定的Activity的onCreate方法已经执行完成并返回,在该方法内可以进行与Activity交互的UI操作,当执行onActivityCreated()的时候 activity的onCreate才刚完成。所以在onActivityCreated()调用之前 activity的onCreate可能还没有完成,所以不能再onCreateView()中进行 与activity有交互的UI操作,UI交互操作可以在onActivityCreated()里面进行。
  2. onStart()
    和activity一致,启动Fragement 启动时回调,,此时Fragement由不可见变为可见状态。
  3. onResume()
    执行该方法时,Fragment处于活动状态,用户可与之交互。激活Fragement 进入前台, 可获取焦点时激活。
  4. onPause()
    和activity一致 其他的activity获得焦点,这个Fragment仍然可见,但是用户不能与之交互。第一次调用的时候,指的是 用户 离开这个Fragment(并不是被销毁)。
  5. onStop()
    和activity一致, fragment不可见的, 可能情况:activity被stopped了或者 fragment被移除但被加入到回退栈中,一个stopped的fragment仍然是活着的如果长时间不用也会被移除。
  6. onDestroyView()
    Fragment中的布局被移除时调用。
    表示Fragment销毁相关联的UI布局, 清除所有跟视图相关的资源,但未与Activity解除绑定,依然可以通过onCreateView方法重新创建视图。
  7. onDestroy()
    销毁Fragment。通常按Back键退出或者Fragment被回收时调用此方法。
  8. onDetach()
    Fragment解除与Activity的绑定。在onDestroy方法之后调用。

下面给出activity和fragment同时运行时候的生命周期:

  • 开始启动:
03-10 16:55:57.722 1700-1700/com.liujc.fragmentlife D/MainActivity: Activity onCreate() 方法执行!
03-10 16:55:57.728 1700-1700/com.liujc.fragmentlife D/TestFragment: Fragment onCreate() 方法执行!
03-10 16:55:57.728 1700-1700/com.liujc.fragmentlife D/TestFragment: Fragment onCreateView() 方法执行!
03-10 16:55:57.728 1700-1700/com.liujc.fragmentlife D/TestFragment: 没有保存的数据!
03-10 16:55:57.730 1700-1700/com.liujc.fragmentlife D/TestFragment: Fragment onActivityCreated() 方法执行!
03-10 16:55:57.730 1700-1700/com.liujc.fragmentlife D/MainActivity: Activity onStart() 方法执行!
03-10 16:55:57.730 1700-1700/com.liujc.fragmentlife D/TestFragment: Fragment onStart() 方法执行!
03-10 16:55:57.730 1700-1700/com.liujc.fragmentlife D/MainActivity: Activity onResume() 方法执行!
03-10 16:55:57.730 1700-1700/com.liujc.fragmentlife D/TestFragment: Fragment onResume() 方法执行!

细心的你可能会发现为什么Fragment没走onAttach()方法呢?难道生命周期还有问题不成。其实Fragment的onAttach()方法有2个重载onAttach(Context context)和onAttach(Activity activity),我的测试机用的android 5.0系统,而在API低于 23 的版本中不会去调用onAttach(Context context),只会去调用onAttach(Activity)。然后把两个方法都加上运行一下结果如下:

03-10 17:19:08.539 19010-19010/com.liujc.fragmentlife D/MainActivity: Activity onCreate() 方法执行!
03-10 17:19:08.546 19010-19010/com.liujc.fragmentlife D/TestFragment: Fragment onAttach(Activity activity) 方法执行!
03-10 17:19:08.546 19010-19010/com.liujc.fragmentlife D/TestFragment: Fragment onCreate() 方法执行!
03-10 17:19:08.547 19010-19010/com.liujc.fragmentlife D/TestFragment: Fragment onCreateView() 方法执行!
03-10 17:19:08.547 19010-19010/com.liujc.fragmentlife D/TestFragment: 没有保存的数据!
03-10 17:19:08.548 19010-19010/com.liujc.fragmentlife D/TestFragment: Fragment onActivityCreated() 方法执行!
03-10 17:19:08.548 19010-19010/com.liujc.fragmentlife D/MainActivity: Activity onStart() 方法执行!
03-10 17:19:08.548 19010-19010/com.liujc.fragmentlife D/TestFragment: Fragment onStart() 方法执行!
03-10 17:19:08.548 19010-19010/com.liujc.fragmentlife D/MainActivity: Activity onResume() 方法执行!
03-10 17:19:08.548 19010-19010/com.liujc.fragmentlife D/TestFragment: Fragment onResume() 方法执行!
  • 按下home按键
03-10 17:00:08.455 1700-1700/com.liujc.fragmentlife D/TestFragment: Fragment onPause() 方法执行!
03-10 17:00:08.456 1700-1700/com.liujc.fragmentlife D/MainActivity: Activity onPause() 方法执行!
03-10 17:00:09.048 1700-1700/com.liujc.fragmentlife D/TestFragment: Fragment onSaveInstanceState() 方法执行!
03-10 17:00:09.052 1700-1700/com.liujc.fragmentlife D/TestFragment: Fragment onStop() 方法执行!
03-10 17:00:09.054 1700-1700/com.liujc.fragmentlife D/MainActivity: Activity onStop() 方法执行!
  • 再回到界面
03-10 17:01:20.870 1700-1700/com.liujc.fragmentlife D/MainActivity: Activity onRestart() 方法执行!
03-10 17:01:20.873 1700-1700/com.liujc.fragmentlife D/MainActivity: Activity onStart() 方法执行!
03-10 17:01:20.873 1700-1700/com.liujc.fragmentlife D/TestFragment: Fragment onStart() 方法执行!
03-10 17:01:20.873 1700-1700/com.liujc.fragmentlife D/MainActivity: Activity onResume() 方法执行!
03-10 17:01:20.873 1700-1700/com.liujc.fragmentlife D/TestFragment: Fragment onResume() 方法执行!
  • 销毁activity
03-10 17:05:53.900 22559-22559/com.liujc.fragmentlife D/TestFragment: Fragment onPause() 方法执行!
03-10 17:05:53.901 22559-22559/com.liujc.fragmentlife D/MainActivity: Activity onPause() 方法执行!
03-10 17:05:54.435 22559-22559/com.liujc.fragmentlife D/TestFragment: Fragment onStop() 方法执行!
03-10 17:05:54.435 22559-22559/com.liujc.fragmentlife D/MainActivity: Activity onStop() 方法执行!
03-10 17:05:54.437 22559-22559/com.liujc.fragmentlife D/TestFragment: Fragment onDestroyView() 方法执行!
03-10 17:05:54.441 22559-22559/com.liujc.fragmentlife D/TestFragment: Fragment onDestroy() 方法执行!
03-10 17:05:54.441 22559-22559/com.liujc.fragmentlife D/TestFragment: Fragment onDetach() 方法执行!
03-10 17:05:54.441 22559-22559/com.liujc.fragmentlife D/MainActivity: Activity onDestroy() 方法执行!

可以看出 当现实fragment的时候都先执行activity方法,当销毁的时候都是现执行 fragment的方法,这样更好理解fragment是嵌套在activity中。

二、将Fragment添加到Activity之中

可以通过在Activity布局文件中声明Fragment,用Fragment标签把Fragment插入到Activity的布局中,或者是用应用程序源码将它添加到一个存在的ViewGroup中。但Fragment并不是一个定要作为Activity布局的一部分,Fragment也可以为Activity隐身工作。

  1. 在activity的布局文件里声明fragment。
    可以像为view一样为fragment指定布局属性。例如:

     
        
        
    

fragment标签中的android:name 属性指定了布局中实例化的Fragment类。
当系统创建activity布局时,它实例化了布局文件中指定的每一个fragment,并为它们调用onCreateView()函数,以获取每一个fragment的布局。系统直接在元素的位置插入fragment返回的View。
  注意:每个fragment都需要一个唯一的标识,如果重启activity,系统可用来恢复fragment(并且可用来捕捉fragment的事务处理,例如移除)。
为fragment提供ID有三种方法:

  • 用android:id属性提供一个唯一的标识。
  • 用android:tag属性提供一个唯一的字符串。
  • 如果上述两个属性都没有,系统会使用其容器视图(view)的ID。
  1. 通过编码将fragment添加到已存在的ViewGroup中。
    在activity运行的任何时候,你都可以将fragment添加到activity布局中。要管理activity中的fragment,可以使用FragmentManager。可以通过在activity中调用getFragmentManager()获得。使用FragmentManager 可以做如下事情,包括:
  • 使用findFragmentById()(用于在activity布局中提供有界面的fragment)或者findFragmentByTag()获取activity中存在的fragment(用于有界面或者没有界面的fragment)。
  • 使用popBackStack()(模仿用户的BACK命令)从后台栈弹出fragment。
  • 使用addOnBackStackChangedListener()注册一个监听后台栈变化的监听器。

在Android中,对Fragment的事务操作都是通过FragmentTransaction来执行。
FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
操作大致可以分为两类:

  • 显示:add()replace()show()attach()
    **transaction.add() **
    往Activity中添加一个Fragment。
    **transaction.replace() **
    使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体。
    **transaction.show() **
    显示之前隐藏的Fragment。
    **attach() **
    重建view视图,附加到UI上并显示。
  • 隐藏:remove()hide()detach()
    ** transaction.remove() **
    从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁。
    transaction.hide()
    隐藏当前的Fragment,仅仅是设为不可见,并不会销毁。
    detach()
    会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。

注意:

  • 调用show() & hide()方法时,Fragment的生命周期方法并不会被执行,仅仅是Fragment的View被显示或者​隐藏。
  • 执行replace()时(至少两个Fragment),会执行第二个Fragment的onAttach()方法、执行第一个Fragment的onPause()-onDetach()方法,同时containerView会detach第一个Fragment的View。
  • 执行add()方法执行onAttach()-onResume()的生命周期,相对的remove()就是执行完成剩下的onPause()-onDetach()周期。

add方式实现fragment的效果就是:切换fragment时不会重新创建,是什么样子切换回来还是什么样子;
用replace的效果就是:切换fragment时每次都会重新创建初始化。
从Activity中取得FragmentTransaction的实例:

FragmentManager fragmentManager = getFragmentManager() 
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

用add()函数添加fragment,并指定要添加的fragment以及要将其插入到哪个视图(view)之中(注意commit事务):

ExampleFragment fragment = new ExampleFragment();
    fragmentTransaction.add(R.id.fragment_container, fragment);
    fragmentTransaction.commit();
  1. 添加没有界面的fragment。
    也可以使用fragment为activity提供后台动作,却不呈现多余的用户界面。
      想要添加没有界面的fragment ,可以使用add(Fragment, String)(为fragment提供一个唯一的字符串“tag”,而不是视图(view)ID)。这样添加了fragment,但是,因为还没有关联到activity布局中的视图(view) ,收不到onCreateView()的调用。所以不需要实现这个方法。对于无界面fragment,字符串标签是唯一识别它的方法。如果之后想从activity中取到fragment,需要使用findFragmentByTag()。

三、Fragment与Activity交互

  • Activity中已经有了该Fragment的引用,直接通过该引用进行交互。
    如果没引用可以通过调用fragment的函数findFragmentById()或者findFragmentByTag(),从FragmentManager中获取Fragment的索引,例如:
    ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
  • 在Fragment中可以通过getActivity得到当前绑定的Activity的实例。
  • 创建activity事件回调函数,在fragment内部定义一个回调接口,宿主activity来实现它。

四、Fragment事务后台栈

在调用commit()之前,可以将事务添加到fragment事务后台栈中(通过调用addToBackStatck())。这个后台栈由activity管理,并且允许用户通过按BACK键回退到前一个fragment状态。
下面的代码中一个fragment代替另一个fragment,并且将之前的fragment状态保留在后台栈中:

Fragment newFragment = new ExampleFragment();
 FragmentTransaction transaction = getFragmentManager().beginTransaction();
 
 transaction.replace(R.id.fragment_container, newFragment);
 transaction.addToBackStack(null);

 transaction.commit();

注意:

  • 如果添加多个变更事务(例如另一个add()或者remove())并调用addToBackStack(),那么在调用commit()之前的所有应用的变更被作为一个单独的事务添加到后台栈中,并且BACK键可以将它们一起回退。
  • 当移除一个fragment时,如果调用了addToBackStack(),那么之后fragment会被停止,如果用户回退,它将被恢复过来。
  • 调用commit()并不立刻执行事务,相反,而是采取预约方式,一旦activity的界面线程(主线程)准备好便可运行起来。然而,如果有必要的话,你可以从界面线程调用executePendingTransations()立即执行由commit()提交的事务。
  • 只能在activity保存状态(当用户离开activity时)之前用commit()提交事务。如果你尝试在那时之后提交,会抛出一个异常。这是因为如果activity需要被恢复,提交后的状态会被丢失。对于这类丢失提交的情况,可使用commitAllowingStateLoss()。

五、Fragment的setUserVisibleHint()

Android应用开发过程中,ViewPager同时加载多个fragment,以实现多tab页面快速切换, 但是fragment初始化时若加载的内容较多,就可能导致整个应用启动速度缓慢,影响用户体验。 为了提高用户体验,我们会使用一些懒加载方案,实现加载延迟。这时我们会用到getUserVisibleHint()与setUserVisibleHint()这两个方法。

/**
*
* @param isVisibleToUser true if this fragment's UI is currently visible to the user (default),
*                        false if it is not.
*/
public void setUserVisibleHint(boolean isVisibleToUser) {
   if (!mUserVisibleHint && isVisibleToUser && mState < STARTED) {
       mFragmentManager.performPendingDeferredStart(this);
   }
   mUserVisibleHint = isVisibleToUser;
   mDeferStart = !isVisibleToUser;
}

/**
 * @return The current value of the user-visible hint on this fragment.
 * @see #setUserVisibleHint(boolean)
 */
public boolean getUserVisibleHint() {
    return mUserVisibleHint;
}

从上述源码注释我们可以看出,当fragment被用户可见时,setUserVisibleHint()会调用且传入true值,当fragment不被用户可见时,setUserVisibleHint()则得到false值。而在传统的fragment生命周期里也看不到这个函数。可以看出其实这个setUserVisibleHint()方法算是手动调用的,并不是在Fragment的生命周期中自动调用。

你可能感兴趣的:(Fragment应用之简述)