Fragment分四个部分出题:

1、为什么Fragment被称为第五大组件

2、Fragment生命周期

3、Fragment的通信

4、Fragment管理器FragmentManager

为什么Fragment被称为第五大组件

1)为什么会出现Fragment:解决屏幕碎片化的问题

2)Fragment加载到Activity中的方法

   ①静态加载



   ②动态加载:
//第一步:获得FragmentTransaction
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
//第二步:使用FragmentTransaction的add方法将Fragment对象加入Fragment栈中
ft.add(R.id.fragment_container,new RightFragment(),"rightFragment");
ft.addToBackStack("rightFragment");
//提交事务
ft.commit();

Fragment的生命周期

Fragment生命周期方法含义:

public void onAttach(Context context)

onAttach()方法会在Fragment与Activity窗口关联后立刻调用。从该方法开始,就可以通过Fragment.getActivity()方法获取与Fragment关联的Activtiy窗口对象,但因为Fragment的控件未初始化,所以不能够操作控件。

public void onCreate(Bundle savedInstanceState)

在调用完onAttach()执行完之后,立即就会调用onCreate()方法,可以在Bundle对象中获取一些在Activity中传过来的数据。通常会在该方法中读取保存的转态,获取或初始化一些数据。在该方法中不要进行耗时操作,不然Activity窗口不会显示。

public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)

该方法是Fragment很重要的一个生命周期方法,因为会在该方法中创建Fragment显示的View,其中inflater是用来装载布局文件的,container是<fragment>标签的父标签对应对象,saveInstanceState参数可以获取Fragment保存的转态,如果未保存那么就为null。

public void onViewCreated(View view,Bundle savedInstanceState)

Android在创建完Fragment中的View对象之后,会立刻回调该方法。其中view参数就是onCreateView中返回的view,而bundle对象用于一般用途。

public void onActivityCreated(Bundle savedInstanceState)

在Activity的onCreate()方法执行完之后,Android系统会立刻调用该方法,表示Activity窗口已经初始化完成,从这一个时候开始,就可以在Fragment中使用getActivity().findViewById(R.id.xxx);来操作Activity中的view了。

public void onStart()

这个没啥可讲的,但是一个细节需要知道,当系统调用该方法的时候,fragment已经显示在UI上了,但还不能进行互动,因为onResume()方法还没有执行完。

public void onResume()

该方法为fragment从创建到显示Android系统调用的最后一个生命周期方法,调用完该方法时候,fragment就可以与用户互动了。

public void onPause()

fragment由活动状态变成非活跃执行的第一个回调方法,通常可以在这个方法中保存一些需要临时暂停的工作。例如:存音乐播放速度,然后在onResume()方法中恢复音乐播放进度。

public void onStop()

当onStop()返回的时候,fragment将从屏幕上消失。

public void onDestoryView()

该方法的调用意味着在onCreateView()中创建的视图都将被移除。

public void onDestroy()

Android在Fragment不再使用时会调用该方法,要注意的是~这是Fragment还和Activity是藕断丝连!并且可以获得Fragment对象,但无法对获得的Fragment进行任何操作。

public void onDetach()

为Fragment生命周期中的最后一个方法,当该方法执行完后,Fragment与Activity不再有关联。

Fragment比Activity多了几个额外的生命周期回调方法:

onAttach(Activity):当Fragment和Activity发生关联时使用。

onCreateView(LayoutInflater,ViewGroup,Bundle):创建该Fragment的视图

onActivityCreate(Bundle):当Activity的onCreate()方法返回时调用

onDestoryView():与onCreateView相对应,当该Fragment的视图被移除时调用

onDetach():与onAttach()相对应,当Fragment与Activity关联被取消时调用

注意:除了onCreateView()方法,其他的所有的方法如果你重写了,必须调用父类对于该方法的实现

回退栈的常见方法:

**(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

FragmentPagerAdapter与FragmentStatePagerAdapter的区别

FragmentPagerAdapter适用于页面较少的情况,destroyItem方法中只是调用了fragmentransaction的detach方法

FragmentStatePagerAdapter适用于页面较多的情况,每次切换ViewPager的时候是回收内存的。destroyItem调用了fragmentransaction的remove方法

Fragment的通信

1、Fragment跟Activity的通信:getActivity();

2、Activity中调用Fragment:接口回调

public class MainFragment extends Fragment{
       public FragmentListener mListener; 

      //MainFragment开放的接口 
      public static interface FragmentListener{ 

          //跳到h5页面
         void toH5Page();

         //展示消息
         void showMsg(String str);
       }
       @Override 
      public void onAttach(Activity activity) { 
            super.onAttach(activity); 
            //对传递进来的Activity进行接口转换
             if(activity instance FragmentListener){
                 mListener = ((FragmentListener)activity); 
            }
       }
       ...其他处理代码省略 

       mButton.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {
              msgListener.showMsg("Hello 传递数据给Activity展示");
          }
      });
}
// MainActivity 实现 MainFragment开放的接口 
  public class MainActivity extends FragmentActivity implements FragmentListener{ 
        @override
         public void toH5Page(){... }

        @Override
         public void showMsg(String str) {
            Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
        }

       ...其他处理代码省略
   }

3、Fragment中调用Fragment :findFragmentById

ContentFragment cf = (ContentFragment) getActivity().getFragmentManager().findFragmentById(R.id.content_fg);  
cf.showPro(name);

Fragment管理器FragmentManager

add与replace 的区别:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0324/2639.html

想必题主对于addToBackStack( )这个方法理解不深

这里先解释下这个方法的作用
我们开启一个新的fragment 用下面这种方式

FragmentManager manager = getSupportFragmentManager();
AFragment fragment = new AFragment();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(viewId, fragment);
transaction.addToBackStack();
transaction.commit();

其中对fragment的操作是下面这个方法

transaction.replace(viewId, fragment);

这个方法可以分解成:

transaction.add(viewId, fragment);
transaction.show(fragment);
transaction.hide(preFragment);
transaction.remove(preFragment);

这两种方式是等效的,只是下面的看起来更直白

那么addToBackStack()这个方法究竟做了什么?

调用addToBackStack()后按back键

AFragment 消失,preFragment又出现了,你在fragment的生命周期中加入log就会发现,AFragment销毁,preFragment被重新创建

其实addToBackStack()记录的是一个transaction的操作记录,当你按back键时,相当于调用了

transaction.add(viewId, preFragment);
transaction.show(preFragment);
transaction.hide(fragment);
transaction.remove(fragment);

即transaction操作了100个fragment的行为,一旦按back键,会读取这100个记录,按反方向调用一次 add 变成remove hide 变成show

现在你明白为什么MapFragment不见了吧

Callback.onReplace(R.id.fragment_container,new SettingFragment());

这个封装方法记录的只是SettingFragment代替了MainBizFragment,因此按back键只是反方向调用一次,并没有保存MainBizFragment中已经开启MapFragment这一状态

addToBackStack()保存的是一系列针对一个fragmentTransaction的操作记录

addToBackStack()保存的是一系列针对一个fragmentTransaction的操作记录

addToBackStack()保存的是一系列针对一个fragmentTransaction的操作记录

你只需保存已经开启MapFragment的这一状态就可以了,在MainBizFragment的onResume(或其他更适合的生命周期函数)中判断一下保存的条件,选择性的开启MapFragment即可

使用tab切换Fragment的时候造成重叠问题

我们都知道fragment切换有两种方式:

  1. replace方式
transaction.replace(R.id.content, IndexFragment);
  1. add-hide-show方式
transaction.add(R.id.content, IndexFragment);
transaction.hide(otherfragment);
transaction.show(thisfragment);

而上面按钮中出现bug的就是采用第二种方式。然后我们来分析下用add,hide,show为什么出现这种bug,我把每个操作都打印出了以下日志:

复现bug的操作是:

1.首先打开,默认选中的是第一个tab,如上面的一张图片正常那样。

2.切换到tab2,并把tab1 hide掉;

3.再切回到tab1,并不会触发tab1对应fragment的任何生命周期;

4.然后home键进入后台,我在activity的onPause()中手动对IndexFragment赋空,模拟长时间后台,系统销毁了该引用

IndexFragment=null;

5.再次启动,其实tab1 的fragment实例在内存中还在,只是他的引用被销毁了。

6.再切到tab2,这里其实是先把tab1的hide,在show tab2,但是tab1 的fragment引用为空,所以无法hide,就出现了tab2叠在tab1上的花屏情况。

7.再切到tab1,tab1就会重复创建对象。

使用replace方式,虽然这种方式会避免上述的bug,但也是重复创建了对象。因为replace方式,对应的FrameLayout只有一 层,而add方式,这个FrameLayout其实有2层。但是这种方式的缺点是:每次replace会把生命周期全部执行一遍,如果在这些生命周期函数 里拉取数据的话,就会不断重复的加载刷新数据

那么最合适的处理方式是这样的:

1.在add的时候,加上一个tab参数
transaction.add(R.id.content, IndexFragment,”Tab1″);
2.然后当IndexFragment引用被回收置空的话,先通过
IndexFragment=FragmentManager.findFragmentByTag(“Tab1″);
找到对应的引用,然后继续上面的hide,show;

results matching ""

    No results matching ""