现在的位置: 首页 > 综合 > 正文

Android Fragment

2018年07月31日 ⁄ 综合 ⁄ 共 4134字 ⁄ 字号 评论关闭

对于Fragment的使用,一方面Activity需要在布局中为Fragment安排位置,另一方面需要管理好Fragment的生命周期。Activity中有个FragmentManager,其内部维护fragment队列,以及fragment事务的回退栈。



为什么需要判null呢?主要是因为,当Activity因为配置发生改变(屏幕旋转)或者内存不足被系统杀死,造成重新创建时,我们的fragment会被保存下来,但是会创建新的FragmentManager,新的FragmentManager会首先会去获取保存下来的fragment队列,重建fragment队列,从而恢复之前的状态。

 

希望保留用户操作的面板,你可以使用hideshow;我不希望保留用户操作,你可以使用remove(),然后add()

removedetach有一点细微的区别,在不考虑回退栈的情况下,remove会销毁整个Fragment实例,而detach则只是销毁其视图结构,实例并不会被销毁。那么二者怎么取舍使用呢?如果你的当前Activity一直存在,那么在不希望保留用户操作的时候,你可以优先使用detach

管理Fragment回退栈:

如何添加一个Fragment事务到回退栈:FragmentTransaction.addToBackStack(String)

例子:

MainActivity.java直接将FragmentOne添加到布局文件中的FrameLayout中,注意这里并没有调用FragmentTransaction.addToBackStack(String),因为我不喜欢在当前显示时,点击Back键出现白板。

@Override  
    protected void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        requestWindowFeature(Window.FEATURE_NO_TITLE);  
        setContentView(R.layout.activity_main);  
  
        FragmentManager fm = getFragmentManager();  
        FragmentTransaction tx = fm.beginTransaction();  
        <strong>tx.add(R.id.id_content, new FragmentOne(),"ONE"); </strong>
        tx.commit();  
    } 

接下来FragmentOne

@Override  
    public void onClick(View v)  
    {  
        FragmentTwo fTwo = new FragmentTwo();  
        FragmentManager fm = getFragmentManager();  
        FragmentTransaction tx = fm.beginTransaction();  
         <strong>tx.replace(R.id.id_content, fTwo, "TWO");  
        tx.addToBackStack(null); </strong>
        tx.commit();  
  
    }  

我们在点击FragmentOne中的按钮时,使用了replace方法,如果你看了前一篇博客,一定记得replaceremoveadd的合体,并且如果不添加事务到回退栈,前一个Fragment实例会被销毁。这里很明显,我们调用tx.addToBackStack(null);将当前的事务添加到了回退栈,所以FragmentOne实例不会被销毁,但是视图层次依然会被销毁,即会调用onDestoryViewonCreateView(就是这里没有保留用户操作)

接下来FragmentTwo---这里保留了用户操作

    public void onClick(View v)  
    {  
        FragmentThree fThree = new FragmentThree();  
        FragmentManager fm = getFragmentManager();  
        FragmentTransaction tx = fm.beginTransaction();  
      <strong> tx.hide(this);  
        tx.add(R.id.id_content , fThree, "THREE");  
//      tx.replace(R.id.id_content, fThree, "THREE");  
        tx.addToBackStack(null);</strong>
        tx.commit();  
    }  

如何处理运行时配置发生变化:只有在savedInstanceState==null时,才进行创建Fragment实例

屏幕发生旋转,当你的应用被至于后台(例如用户点击了home,长时间没有返回的时候,你的应用也会被重新启动。比如上例:如果你把上面的例子你至于FragmentThree界面,然后处于后台状态,长时间后你会发现当你再次通过home打开时,上面FragmentThreeFragmentOne叠加在一起

Fragment Arguments:Fragment 和activity解耦

有哥们会说,这个简单?看我的代码(问题代码):

public class ContentFragment extends Fragment  
{       
    private String mArgument ;   
    public static final String ARGUMENT ="argument";  
    @Override  
    public void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);         
      <del> mArgument = getActivity().getIntent().getStringExtra(ARGUMENT); </del>         
    } 

我们直接在Fragment的onCreate中,拿到宿主Activty,宿主Activity中肯定能通过getIntent拿到Intent,然后通过get方法,随意拿参数~~

这么写,功能上是实现了,但是呢?存在一个大问题:我们用Fragment的一个很大的原因,就是为了复用。你这么写,相当于这个Fragment已经完全和当前这个宿主Activity绑定了,复用直接废了~~~所以呢?我们换种方式,推荐使用arguments来创建Fragment。

<span style="color:#333333;">public class ContentFragment extends Fragment  
{   
    private String mArgument;  
    public static final String ARGUMENT = "argument";  
    @Override  
    public void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        // mArgument = getActivity().getIntent().getStringExtra(ARGUMENT);  
        Bundle bundle = getArguments();  
        if (bundle != null)  
            mArgument = bundle.getString(ARGUMENT);  
  
    }  
    /** 
     * 传入需要的参数,设置给arguments 
     */  
    public static ContentFragment newInstance(String argument)  
    {  
       </span><span style="color:#ff0000;"> Bundle bundle = new Bundle();  
        bundle.putString(ARGUMENT, argument);  
        ContentFragment contentFragment = new ContentFragment();  
        contentFragment.setArguments(bundle);  </span><span style="color:#333333;">
        return contentFragment;  
    }  </span>

Fragment的startActivityForResult

startActivityForResult(intent, REQUEST_DETAIL); 

  1. Intent intent = new Intent();  
  2.             intent.putExtra(RESPONSE, "good");  
  3.             getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent); 

FragmentPagerAdapter与FragmentStatePagerAdapter

主要区别就在与对于fragment是否销毁,下面细说:

FragmentPagerAdapter:对于不再需要的fragment,选择调用detach方法,仅销毁视图,并不会销毁fragment实例。

FragmentStatePagerAdapter:会销毁不再需要的fragment,当当前事务提交以后,会彻底的将fragmeng从当前Activity的FragmentManager中移除,state标明,销毁时,会将其onSaveInstanceState(Bundle outState)中的bundle信息保存下来,当用户切换回来,可以通过该bundle恢复生成新的fragment,也就是说,你可以在onSaveInstanceState(Bundle outState)方法中保存一些数据,在onCreate中进行恢复创建。

如上所说,使用FragmentStatePagerAdapter当然更省内存,但是销毁新建也是需要时间的。一般情况下,如果你是制作主页面,就3、4个Tab,那么可以选择使用FragmentPagerAdapter,如果你是用于ViewPager展示数量特别多的条目时,那么建议使用FragmentStatePagerAdapter。

抱歉!评论已关闭.