安卓开发大神级人物 JakeWharton 前不久在接受采访时提出一个颇具争议而又没有给出原因的建议:一个 App 只需要一个 Activity ,你可以使用 Fragments,只是别用 Fragments 回退栈。
针对这一言论,有关 JakeWharton 建议的背后原因的一个提问迅速在 Reddit 国外网站的安卓开发频道引发热评。
众多安卓开发人员纷纷提出自己的见解。其中获赞最高的一条,甚至得到 JakeWharton 本人的亲自赞评。
我们来看看这条回答都提到了哪些内容,对 Activity 和 Fragment 之间的爱恨情仇有何独到的见解,凭什么能得到 JakeWharton 本尊的青睐有加。
因为 Activity 是一个程序入口。你可以将其视为 app 的一个
函数。站在用户的立场上,通常你进入 app 的方式可能包括以下几种:
- main
函数入口);
- main
函数入口的通知栏,并且导航到 app 的指定位置;
- main
请求的 intents;
- share
差不多类似这些场景。
但是,如果你真的不用分享和来自应用的 intents 的话,并且唯一的程序入口就是 launcher 桌面,别为每一个页面创建一个新的入口。这样做其实没有意义。为什么没有意义?因为这种场景下,进程死掉后 launcher 能够启动任何你应用中的 Activity 页面。
Fragments 是处理生命周期事件的视图控制器,并且非常不错。然而,Fragments 回退栈简直垃圾;回退栈变化监听器总是不正常地被调用( 1 次 transaction 三次调用?),并且不告诉你调用什么,而在恢复事务时也不知道哪些 fragments 是可用的。
你可以给事务添加 tag 标签,然后从栈中弹出操作,但是仅仅是一个
的操作流程就相当繁琐了。
- main -> Events -> Details(id=123)
同样的,一旦你将一个 Fragment 放进回退栈中,我个人不知道它的生命周期开始做什么。我曾经遇到过一个后台中的 fragment 被调用四次
方法,我甚至不知道究竟怎么了。而没有位于回退栈中的 Fragments 是可以被预见的。它们的动画支持有点古怪,但至少它们还能使用。
- onCreateView()
所以如果你想知道哪些 Fragments 是你能够操作的并且哪些 views 是你正在展示的并且能够在你自己的导航状态控制之中,那么你应该自己处理导航操作。把“应用逻辑”抽象化到一个 presenter(亦枫注:MVP 模式)中听起来来很棒,但是你是不是脱离了应用视图层里面的真实情况?
但是单一 activity 的优势是什么?
更简单的生命周期处理(例如,当 app 进入后台时,你只需要处理
方法),更少错误空间,和更多控制。同样的,你可以移动视图层外面的导航状态到 domain 层,或者至少到 presenter 中。不需要太多
- onStop
之类的东西,你只需要在你的 presenter 或者 ViewModel 或者无论哪些时髦的用法中使用
- view.navigateToDetail(songId)
就行。借助一个合适的库,当你到了
- backstack.goTo(SongKey.create(songId))
时它会自动将这些导航调用加入队列,并且不会致使 fragment 事务发生崩溃,非常得好。
- onResume
尽管 Google 给出的案例也在用
,我有使用
- commitAllowingStateLoss()
的动画爱好。在我看来,单个 activity 能够看得见的好处就是,页面间共享 views 的能力,取代通过使用
- commitNow()
标签在 18 个布局文件重复视图。其他当然是更简单的导航操作。
- <include
以上便是深得 JakeWharton 大神心意的一条回答。话虽如此,但是系统 Fragment 存在的未解之谜或者说出乎你意料的坑实在太多。如果一定要在多 activity 部分 fragments 和单 activity 多 fragments 之间选择的话,我想不只是我,很多人还是毫不犹豫地选择前者。
更多讨论内容,参见:
www.reddit.com/r/androidde…
备注:关于使用 Fragments 的那些道道,我之前也写过相关总结性的文章来,感兴趣地不妨去我的博客搜索看看。
关于我:亦枫,博客地址:yifeng.studio/,新浪微博:IT亦枫
微信扫描二维码,欢迎关注我的个人公众号:安卓笔记侠
不仅分享我的原创技术文章,还有程序员的职场遐想
彩蛋:公众号回复关键字“面试资料”,获取 BAT 面试大牛为你准备的全套面试资料!
来源: https://juejin.im/post/5a2faecd6fb9a045263b8fb4