我发现很多Android程序员写代码时,都喜欢把业务逻辑和UI的更新展示这两块代码都交集在Activity类上,最终往往会产出非常复杂或者上千行代码的类。但如果在开始做一个功能时,就把各种扩展和优化都考虑尽了,也不切实际,而且也有点过度设计的意味。也许因为这个原因,很多人在写代码时就干脆不考虑设计了,直接混在一起要哪块写哪块。
Google也许也看到了这个问题,在Android 3.0版本引进了Fragment,使用官方的support包(android-support-v4)也可以支持在3.0以前的版本使用。之前有一次老外的电话面试,也问到了Fragment方面的问题,那时Fragment刚面世不久,我发现老外都比较潮,喜欢尝试新的东西。
面试题:两个Fragment之间如何进行通信?
先说一下Fragment,中文可以叫片段,其实我们也可以把它理解成一个组件,它有自己的生命周期(回调函数),可以组织UI和业务逻辑。但它不像Android的四大组件(Activity, Service, BroadcastReceiver和ContentProvider)那样可以独立存在,它必须要依附于Activity,由Activity中的FragmentManager实例来管理它的生命周期。
Google最初引入Fragment主要是为了给大屏幕(如平板电脑)上更加动态和灵活的 UI 设计提供支持,看一下下图你就明白了:
我们可以在多个Activity中重复使用某个片段,并且可以按我们的需求把不同的片段组合在一个界面中,好处显而易见,减少工作量提高了代码的可重用性。
也就是说每个片段是相互独立的,如上图所示,Fragment A并不知道这个Activity中是否存在Fragment B。这样一来就会产生Fragment之间通信的问题(比如Fragment A点击了列表的一项,Fragment B的内容要进行更新),当然这个问题的答案并不是唯一的,有很多种做法。不过,最基础的做法你应该了解一下,就是通过Activity进行通信。
尽管Fragment是作为独立于Activity的对象实现,并且可在多个Activity内使用,但片段的给定实例会直接绑定到包含它的 Activity。具体地说,片段可以通过getActivity()访问Activity实例。
同样地,Activity也可以使用findFragmentById()或findFragmentByTag(),通过从FragmentManager获取对Fragment的引用来调用片段中的方法。
知道这些基础,你应该很清楚怎么进行通信了。不过我们建议的方式是面向接口编程,在Fragment中getActivity获取到的Activity实例应该是实现了我们某个接口的实例,即在Fragment的代码中不应该出现某个具体的Activity类。
Fragment的生命周期
如果你喜欢使用Fragment,一定要清楚这些生命周期的方法,哪个方法会创建视图(View),哪个会销毁视图,这样才能更好的使用它们。
先来看看官方的Fragmenet生命周期和Activity生命周期的对应关系图:
是不是觉得,好像也没有多复杂,只是在一些对应的Activity生命周期方法上进行了细分。
我们再看看反对使用Fragment的人是如何看待Fragment的生命周期的:
是不是头都大了?简单地说Fragment的生命周期并不像官方描述的那样简单,感兴趣的朋友可以看看这篇文章:我为什么主张反对使用Android Fragment。
Fragment虽然在某种程度上实现了代码复用,但并没有将UI和逻辑分离,而且引入了复杂的生命周期,在一定程度上也限制了它的使用。如Fragment嵌套Fragment可能会遇到嵌套的Fragment接收不到onActivityResult事件之类的问题。
不过,我也看到有人是这样使用Fragment的,创建一个没有UI的Fragment仅将它做为保存状态的工具使用。因为Fragment也有onSaveInstanceState方法,可以在里面对状态进行处理,而且系统回收Activity后再使用Activity时会帮我们恢复Fragment的状态。
关于Fragment还有很多细节,如果面试者经常使用的话,还可以问问“如何管理Fragment回退栈”或者“FragmentTransaction中remove和detach的区别”等问题。
小结
其实我也不喜欢用Fragment,因为我发现写Fragment和写Activity的感觉是一样的,UI加逻辑,也许是在为我面对的很多项目都不需要考虑平板的原因。不过即使考虑平板,我们一样可以通过自定义的View去实现。有时候我们使用Fragment,是因为考虑到使用它进行界面切换比Activity切换的代价要小很多。
面试时,面试者不一定能记起所有的细节,但我认为一些基础机制(或原理或者默认习俗)都是应该了解的,不然我会认为面试者不是经历的项目太少,就是没有进行系统性的学习,简单说就是,你可以没有使用过Fragment(这并不丢人),但你一定要了解一下Fragment是什么东西吧?