我为什么主张反对使用Android Fragment

——欢迎转载,请注明出处 ,未经本人同意请勿用于商业用途,谢谢——

原文链接:https://corner.squareup.com/2014/10/advocating-against-android-fragments.html

本文Gitbooks链接:

最近我在Droidcon Paris举办了一场技术讲座,我讲述了Square公司在使用Android fragments时遇到的问题,以及其他人如何避免使用fragments。

在2011年,基于以下原因我们决定在项目中使用fragments:

自从2011年以来,我们为Square找到了更好的选择。

关于fragments你所不知道的复杂的生命周期

Android中,Context是一个上帝对象(god object),而Activity是具有附加生命周期的context。具有生命周期的上帝对象?有点讽刺的意味。Fragments不是上帝对象,但它们为了弥补这一点,实现了及其复杂的生命周期。

Steve Pomeroy为Fragments复杂的生命周期制作了一张图表看起来并不可爱:

上面Fragments的生命周期使得开发者很难弄清楚在每个回调处要做什么,这些回调是同步的还是异步的?顺序如何?

难以调试

当你的app出现bug,你使用调试器并一步一步执行代码以便了解到底发生了什么,这通常能很好地工作,直到你遇到了FragmentManagerImpl:它是地雷。

下面这段代码很难跟踪和调试,这使得很难正确的修复app中的bug:

switch (f.mState) {case Fragment.INITIALIZING:if (f.mSavedFragmentState != null) {f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(FragmentManagerImpl.VIEW_STATE_TAG);f.mTarget = getFragment(f.mSavedFragmentState,FragmentManagerImpl.TARGET_STATE_TAG);if (f.mTarget != null) {f.mTargetRequestCode = f.mSavedFragmentState.getInt(FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);}f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);if (!f.mUserVisibleHint) {f.mDeferStart = true;if (newState > Fragment.STOPPED) {newState = Fragment.STOPPED;}}}// …}

如果你曾经遇到屏幕旋转时旧的unattached的fragment重新创建,那么你应该知道我在谈论什么(不要让我从嵌套fragments讲起)。

正如Coding Horror所说,根据法律要求我需要附上这个动画的链接。

经过多年深入的分析,我得到的结论是WTFs/min = 2^fragment的个数。

View controllers?没这么快

由于fragments创建,绑定和配置views,它们包含了大量的视图相关的代码。这实际上意味着业务逻辑没有和视图代码解耦-这使得很难针对fragments编写单元测试。

Fragment事务

Fragment事务使得你可以执行一系列fragment操作,不幸的是,提交事务是异步的,而且是附加在主线程handler队列尾部的。当你的app接收到多个点击事件或者配置发生变化时,将处于不可知的状态。

FragmentTransaction {int commitInternal(boolean allowStateLoss) {if (mCommitted)throw new IllegalStateException(“commit already called”);mCommitted = true;if (mAddToBackStack) {mIndex = mManager.allocBackStackIndex(this);} else {mIndex = -1;}mManager.enqueueAction(this, allowStateLoss);return mIndex;}}Fragment创建魔法

Fragment实例可以由你或者fragment manager创建。下面代码似乎很合理:

DialogFragment dialogFragment = new DialogFragment() { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { … }};dialogFragment.show(fragmentManager, tag);

然而,当恢复activity实例的状态时,fragment manager可能会尝试通过反射机制重新创建这个fragment类的实例。由于这是一个匿名内部类,它的构造函数有一个隐藏的参数,持有外部类的引用。

android.support.v4.app.Fragment$InstantiationException:Unable to instantiate fragment com.squareup.MyActivity$1:make sure class name exists, is public, and has an emptyconstructor that is publicFragments的经验教训

尽管存在缺点,fragments教给我们宝贵的教训,让我们在编写app的时候可以重用:

响应式UI:fragments vs 自定义viewsFragments

让我们看一个fragment的简单例子,一个列表和详情UI。

HeadlinesFragment是一个简单的列表:

{ OnHeadlineSelectedListener mCallback; {void onArticleSelected(int position); } (Bundle savedInstanceState) {super.onCreate(savedInstanceState);setListAdapter(new ArrayAdapter<String>(getActivity(),R.layout.fragment_list,Ipsum.Headlines)); } (Activity activity) {super.onAttach(activity);mCallback = (OnHeadlineSelectedListener) activity; } (ListView l, View v, int position, long id) {mCallback.onArticleSelected(position);getListView().setItemChecked(position, true); }}于是夜莺会在黎明到来之前勇敢的将胸膛顶住蔷薇的刺,

我为什么主张反对使用Android Fragment

相关文章:

你感兴趣的文章:

标签云: