7

Android Fragment 你应该知道的一切

 3 years ago
source link: https://blog.csdn.net/lmj623565791/article/details/42628537
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Android Fragment 你应该知道的一切_Hongyang-CSDN博客_android fragement

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/42628537,本文出自:【张鸿洋的博客】

很久以前写过两篇Fragment的介绍,主要就是介绍其功能:Android Fragment 真正的完全解析(上)Android Fragment 真正的完全解析(下) 有兴趣的可以凑合看下。之前的博客属于怎么使用Fragment,本文目标教你如何用好Fragment,即Fragment的一些使用的建议,(多数内容来自:android programming the big nerd ranch guide 一书,直接百度,你懂的,虽然是基础书籍,还是很值得一看的)。

首先我们简单回顾一下,相信大家对Fragment的都不陌生,对于Fragment的使用,一方面Activity需要在布局中为Fragment安排位置,另一方面需要管理好Fragment的生命周期。Activity中有个FragmentManager,其内部维护fragment队列,以及fragment事务的回退栈。

一般情况下,我们在Activity里面会这么添加Fragment:

针对上面代码,问两个问题:

1、为什么需要判null呢?

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

2、add(R.id.id_fragment_container,mContentFragment)中的布局的id有何作用?

一方面呢,是告知FragmentManager,此fragment的位置;另一方面是此fragment的唯一标识;就像我们上面通过fm.findFragmentById(R.id.id_fragment_container)查找~~

好了,简单回顾了一下基本用法,具体的还请参考上面的博客或者其他资料,接下来,介绍一些使用的意见~~

2、Fragment Arguments

下面描述一个简单的场景,比如我们某个按钮触发Activity跳转,需要通过Intent传递参数到目标Activity的Fragment中,那么此Fragment如何获取当前的Intent的值呢?

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

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

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

给Fragment添加newInstance方法,将需要的参数传入,设置到bundle中,然后setArguments(bundle),最后在onCreate中进行获取;

这样就完成了Fragment和Activity间的解耦。当然了这里需要注意:

setArguments方法必须在fragment创建以后,添加给Activity前完成。千万不要,首先调用了add,然后设置arguments。

3、Fragment的startActivityForResult

依旧是一个简单的场景:两个Fragment,一个展示文章列表的Fragment(叫做ListTitleFragment),一个显示详细信息的Fragment(叫做:ContentFragment),当然了,这两个Fragment都有其宿主Activity。

现在,我们点击列表Fragment中的列表项,传入相应的参数,去详细信息的Fragment展示详细的信息,在详细信息页面,用户可以进行点评,当用户点击back以后,我们以往点评结果显示在列表的Fragment对于的列表项中;

也就是说,我们点击跳转到对应Activity的Fragment中,并且希望它能够返回参数,那么我们肯定是使用Fragment.startActivityForResult ; 

在Fragment中存在startActivityForResult()以及onActivityResult()方法,但是呢,没有setResult()方法,用于设置返回的intent,这样我们就需要通过调用getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);。

详细代码:

ListTitleFragment

ContentFragment

贴出了两个Fragment的代码,可以看到我们在ListTitleFragment.onListItemClick,使用startActivityForResult()跳转到目标Activity,在目标Activity的Fragment(ContentFragment)中获取参数,然后调用getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);进行设置返回的数据;最后在ListTitleFragment.onActivityResult()拿到返回的数据进行回显;

为大家以后在遇到类似问题时,提供了解决方案;也说明了一个问题:fragment能够从Activity中接收返回结果,但是其自设无法产生返回结果,只有Activity拥有返回结果。

接下来我要贴一下,这两个Fragment的宿主Activity:

ListTitleActivity

ContentActivity:

有没有发现两个Activity中的代码极其的类似,且使用了同一个布局文件:

activity_single_fragment.xml

为什么要贴这Acticity的代码呢?因为我们项目中,如果原则上使用Fragment,会发现大量类似的代码,那么我们就可以抽象一个Activity出来,托管我们的Single Fragment。

详细见下一节。

4、SingleFragmentActivity

于是抽象出来的Activity的代码为:

那么,有了这个SingleFragmentActivity,我们的ContentActivity和ListTitleActivity也能大变身了~

是不是简洁很多,相信优先使用Fragment的项目,类似的Activity非常多,使用SingleFragmentActivity来简化你的代码吧~~

好了,此代码是来自文章开始推荐的书中的,再次推荐一下~~。

5、FragmentPagerAdapter与FragmentStatePagerAdapter

相信这两个PagerAdapter的子类,大家都不陌生吧~~自从Fragment问世,使用ViewPager再结合上面任何一个实例的制作APP主页的案例特别多~~~

那么这两个类有何区别呢?

主要区别就在与对于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。

篇幅原因,具体的案例就不写了,大家自行测试。

6、Fragment间的数据传递

上面3中,我们展示了,一般的两个Fragment间的数据传递。

那么还有一种比较特殊的情况,就是两个Fragment在同一个Activity中:例如,点击当前Fragment中按钮,弹出一个对话框(DialogFragment),在对话框中的操作需要返回给触发的Fragment中,那么如何数据传递呢?对于对话框的使用推荐:Android 官方推荐 : DialogFragment 创建对话框

我们继续修改我们的代码:现在是ListTitleFragment , ContentFragment , 添加一个对话框:EvaluateDialog,用户点击ContentFragment 内容时弹出一个评价列表,用户选择评价。

现在我们的关注点在于:ContentFragment中如何优雅的拿到EvaluateDialog中返回的评价:

记住我们在一个Activity中,那么肯定不是使用startActivityForResult;但是我们返回的数据,依然在onActivityResult中进行接收。

好了看代码:

ContentFragment

删除了一些无关代码,注意看,我们在onCreateView中为textview添加了click事件,用于弹出我们的dialog,注意一行代码:

dialog.setTargetFragment(ContentFragment.this, REQUEST_EVALUATE);

我们调用了Fragment.setTargetFragment ,这个方法,一般就是用于当前fragment由别的fragment启动,在完成操作后返回数据的,符合我们的需求吧~~~注意,这句很重要。

接下来看EvaluateDialog代码:

重点就是看点击后的setResult了,我们首先判断是否设置了targetFragment,如果设置了,意味我们要返回一些数据到targetFragment。

我们创建intent封装好需要传递数据,最后手动调用onActivityResult进行返回数据~~

最后我们在ContentFragment的onActivityResult接收即可。

ok,终于把这些tips贯穿到一起了,到此我们的Fragment的一些建议的用法就结束了~~~那么,最后提供下源码,也顺便贴个效果图:

源码点击下载


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK