安卓开发Android技术知识Android开发

Fragment应用之简述

2017-04-02  本文已影响373人  闲庭

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

一、Fragment的生命周期

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() 方法执行!
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() 方法执行!
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指定布局属性。例如:
<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"> 
        
        <fragment android:name="com.liujc.test.FragmentOne"
            android:id="@+id/fragment_one"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

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

  1. 通过编码将fragment添加到已存在的ViewGroup中。
    在activity运行的任何时候,你都可以将fragment添加到activity布局中。要管理activity中的fragment,可以使用FragmentManager。可以通过在activity中调用getFragmentManager()获得。使用FragmentManager 可以做如下事情,包括:

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

注意:

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交互

四、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();

注意:

五、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的生命周期中自动调用。

上一篇下一篇

猜你喜欢

热点阅读