android开发安卓界面开发Android面试

Android--Fragment你应该明白的一些疑难点

2017-03-16  本文已影响2870人  wangling90
美女图集02
Fragment概述

Fragment是Activity中用户界面的一个行为或者说是一部分。主要是支持大屏幕上动态显示和更为灵活的去组合或是交换UI组件,通过将Activity的布局分割成若干个fragment,可以在运行时编辑activity的呈现,并且那些变化会被保存在由activity管理的后台栈里面。
Fragment必须总是被嵌入到一个activity之中,并且fragment的生命周期直接接受其宿主activity的生命周期的影响。你可以认为fragment是activity的一个模块零件,它有自己的生命周期,接收它自己的输入的事件,并且可以在activity运行时添加或者删除。
应该将每一个fragment设计为模块化和可复用化的activity组件。也就是说,你可以在多个activity中引用同一个fragment,因为fragment定义了它自己的布局,并且使用它本身生命周期回调的行为。

Fragment生命周期中的那么多方法,快来学习一下吧!go go go

Fragment生命周期方法含义:
Fragment比Activity多了几个额外的生命周期回调方法:
管理fragment生命周期与管理activity生命周期很相像

像activity一样,fragment也有三种状态:

@Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                      Bundle savedInstanceState) { 
            // Inflate the layout for this fragment
           return inflater.inflate(R.layout.example_fragment, 
                                                 container, false);
  }```
inflate()函数需要以下三个参数:
(1).要inflate的布局的资源Id
(2).被inflate的布局的父ViewGroup
(3).一个布尔值,表明在inflate期间被inflate的布局是否应该附上ViewGroup(第二个参数container)。(在这个例子中传入的是false,因为系统已经将被inflate的布局插入到容器中(container)——传入true会在最终的布局里创建一个多余的ViewGroup)

#####Fragment与Activity之间的交互:
* 将Fragment添加到activity之中
可以通过在activtiy布局文件中声明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.example.test.FragmentOne"
            android:id="@+id/fo"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
</LinearLayout>
fragment标签中的android:name属性指定了布局中实例化Fragment类。
当系统创建activity布局时,它实例化了布局文件中指定的每一个fragment,并为它们调用onCeateView()函数,以获取每一个fragment的布局。系统直接在元素的位置插入fragment返回的View。
**注意:每个fragment都需要一个唯一的标识,如果重启activity,系统可用来恢复fragment(并且可用来捕捉fragment的事务处理,例如:移除fragment),为fragment提供了ID有三种方法:**
1:>用android:id属性提供一个唯一的标识
2:>用android:tag属性提供一个唯一的字符串。
3:>如果上述两种属性都没有,系统会使用其容器视图(view)的ID。
**(2).通过编码将fragment添加到已存在的ViewGroup中**
在activity运行的任何时候,你都可以将fragment添加到activity布局中。要管理activity中的fragment,可以使用FragmentManager。可以通过在activity中调用getFragmentManager()获得。使用FragmentManager可以做如下事情,包括:
1:>使用findFragmentById()(用于在activity布局中提供有界面的fragment或者findFragmentByTag()获取activity中存在的fragment(用于有界面或者没有界面的fragment))
2:>使用popBackStack()(模仿用户的Back命令)从后台栈弹出fragment。
3:>使用addOnBackStackChangeListener()注册一个监听后台栈变化的监听器。
在android中,对fragment的事务操作都是通过FragmentTranSaction来执行。操作大致可以分为两类:
1:>显示:add(), replace(), show(), attach()
2:>隐藏:remove(), hide(), detach()
**说明**:调用show() & hide()方法时,Fragment的生命周期方法并不会被执行,仅仅是Fragment的View被显示或者​隐藏。执行replace()时(至少两个Fragment),会执行第二个Fragment的onAttach()方法、执行第一个Fragment的onPause()-onDetach()方法,同时containerView会detach第一个Fragment的View。add()方法执行onAttach()-onResume()的生命周期,相对的remove()就是执行完成剩下的onPause()-onDetach()周期。
可以像下面这样从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();```
**(3).添加没有界面的fragment**
也可以使用fragment为activity提供后台动作,却不呈现多余的用户界面。想要添加没有界面的fragment ,可以使用add(Fragment, String)(为fragment提供一个唯一的字符串“tag”,而不是视图(view)ID)。这样添加了fragment,但是,因为还没有关联到activity布局中的视图(view) ,收不到onCreateView()的调用。所以不需要实现这个方法。对于无界面fragment,字符串标签是唯一识别它的方法。如果之后想从activity中取到fragment,需要使用findFragmentByTag()。 

* Fragment与Activity之间的交互可以通过Fragment.setArguments(Bundle args)以及Fragment.getArguments()来实现。

#####Fragment状态的持久化:
由于Activity会经常性的发生配置变化,所以依附它的Fragment就有需要将其状态保存起来问题。下面有两种常用的方法去将Fragment的状态持久化。
* 方法一
可以通过```protected void onSaveInstanceState(Bundle outState),protected void onRestoreInstanceState(Bundle savedInstanceState)```状态保存和恢复的方法将状态持久化。
* 方法二(更为方便,让Android自动帮我们保存Fragment状态)
**<1>.**我们只需要将Fragment在Activity中作为一个变量整个保存,只要保存了Fragment,那么Fragment的状态就得到保存了,所以我们就可以通过下面方法,进行获取Fragment数据。

FragmentManager.putFragment(Bundle bundle, String key, Fragment
fragment) 是在Activity中保存Fragment的方法。
FragmentManager.getFragment(Bundle bundle, String key)
是在Activity中获取所保存的Frament的方法。```
<2>.很显然,上述<1>中的key就传入Fragment的id,fragment就是你要保存状态的fragment,但,我们注意到上面的两个方法,第一个参数都是Bundle,这就意味着FragmentManager是通过Bundle去保存Fragment的。但是,这个方法仅仅能够保存Fragment中的控件状态,比如说:EditText中用户已经输入的文字(注意:在这里,控件需要设置一个id值,否则Android将不会为我们保存该控件的状态),而Fragment中需要持久化的变量依然会丢失,但依然有解决方法,就是利用方法一!
<3>.下面给出状态的持久化实例代码:

    /** Activity中的代码 **/
    FragmentB fragmentB;

   @Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.fragment_activity);
       if( savedInstanceState != null ){
           fragmentB = (FragmentB) getSupportFragmentManager()
                       .getFragment(savedInstanceState,"fragmentB");
       }
       init();
   }

   @Override
   protected void onSaveInstanceState(Bundle outState) {
       if( fragmentB != null ){
          getSupportFragmentManager()
            .putFragment(outState,"fragmentB",fragmentB);
       }
       super.onSaveInstanceState(outState);
   }

   /** Fragment中保存变量的代码 **/
   @Nullable
   @Override
   public View onCreateView(LayoutInflater inflater, @Nullable 
       ViewGroup container, @Nullable Bundle savedInstanceState) {
       AppLog.e("onCreateView");
       if ( null != savedInstanceState ){
           String savedString = savedInstanceState
                                .getString("string");
           //得到保存下来的string
       }
       View root = inflater.inflate(R.layout.fragment_a,null);
       return root;
   }

   @Override
   public void onSaveInstanceState(Bundle outState) {
       outState.putString("string","anAngryAnt");
       super.onSaveInstanceState(outState);
   }
静态的使用Fragment

1.集成Fragment,重写onCreateView()决定Fragment的布局
2.在Activity中声明此Fragment,就和普通的View一样。

Fragment常用的API

链接:关于getChildFragmentManager()、 getFragmentManager()、getSupportFragmentManager()的使用

    FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
    //往Activity中添加一个Fragment
    transaction.add() 

    transaction.remove() 
    //从Activity中移除一个Fragment,如果被移除的Fragment没有添    加到回退栈
     (回退栈后面会详细说),这个Fragment实例将会被销毁。

    transaction.replace()
    //使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体~

    transaction.hide()
    //隐藏当前的Fragment,仅仅是设为不可见,并不会销毁

    transaction.show()
    //显示之前隐藏的Fragment

    detach()
    //当fragment被加入到回退栈的时候,该方法与*remove()*的作用是相同的,
    //反之,该方法只是将fragment从视图中移除,
    //之后仍然可以通过*attach()*方法重新使用fragment,
    //而调用了*remove()*方法之后,
    //不仅将Fragment从视图中移除,fragment还将不再可用。

    attach()
    //重建view视图,附加到UI上并显示。

    transatcion.commit()
    //提交一个事务

在调用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回退栈
* 跟踪回退栈的状态
我们通过实现```OnBackStackChangedListener```接口来实现回退栈状态跟踪,具体代码如下:

//implements接口
public class XXX implements FragmentManager.OnBackStackChangedListener
//实现接口所要实现的方法
@Override
public void onBackStackChanged() {
//do whatevery you want
}
//设置回退栈监听接口
getSupportFragmentManager().addOnBackStackChangedListener(this);

* 管理回退栈
**(1).```FragmentTransaction.addToBackStack(String)```**
将一个刚刚添加的Fragment加入到回退栈中
**(2).```getSupportFragmentManager().getBackStackEntryCount()```**
获取回退栈中的实体数量
**(3).```getSupportFragmentManager().popBackStack(String name, int flags)```**
根据name立刻弹出栈顶的fragment
**(4).```getSupportFragmentManager().popBackStack(int id, int flags)```**
根据id立刻弹出栈顶的fragment

**结束语:相信自己,一定可以成为自己想成为的那个人的,加油!   ---王令
QQ:2585085940
邮箱:wang91ling@163.com
欢迎大家光临寒舍。**
上一篇下一篇

猜你喜欢

热点阅读