fragmentTransaction.replace()方法的奇怪行为

时间:2017-02-08 06:12:27

标签: android android-fragments

我刚刚创建了一个演示来理解FragmentTransaction的替换方法,但我没有按照Developer Guide获得结果。

活动和片段

public class MainActivity extends AppCompatActivity {

    private int count;
    private Fragment prevFragment;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button button = (Button) findViewById(R.id.activity_main_bv_add);


        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                count++;

                final FragmentTransaction transaction = getFragmentManager().beginTransaction();
                final TestFragment fragment = new TestFragment(count);

                if (count == 1) {
                    transaction.add(R.id.activity_main_rl_container, fragment, fragment.getClass().getSimpleName());

                } else if (count == 5) {
                    transaction.replace(R.id.activity_main_rl_container, fragment, fragment.getClass().getSimpleName());
                    transaction.addToBackStack(null);
                    if (prevFragment != null) {
                        transaction.hide(prevFragment);
                    }
                } else {
                    transaction.add(R.id.activity_main_rl_container, fragment, fragment.getClass().getSimpleName());
                    transaction.addToBackStack(null);
                    if (prevFragment != null) {
                        transaction.hide(prevFragment);
                    }
                }
                prevFragment = fragment;

                transaction.commit();


            }
        });
    }

    public class TestFragment extends Fragment {
        private final String TAG = this.getClass().getSimpleName();
        private int number;


        public TestFragment(final int number) {
            this.number = number;
        }

        public TestFragment() {
        }

        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            Log.e(TAG, "onCreateView : " + number);

            final View view = inflater.inflate(R.layout.row_button, null);

            final Button button = (Button) view.findViewById(R.id.button);
            button.setText("" + number);

            return view;
        }

        @Override
        public void onDestroyView() {
            super.onDestroyView();
            Log.e(TAG, "onDestroyView : " + number);
        }
    }
}

片段xml

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="@color/colorPrimary"
              android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:focusable="false"
        android:focusableInTouchMode="false"
        />

</LinearLayout>

活动xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/activity_currency_select"
                xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:descendantFocusability="blocksDescendants"
    >

    <Button
        android:id="@+id/activity_main_bv_add"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:text="Add More"/>

    <RelativeLayout
        android:id="@+id/activity_main_rl_container"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:layout_below="@id/activity_main_bv_add"
        android:layout_marginTop="20dp"
        android:background="@color/colorAccent"></RelativeLayout>


</RelativeLayout>

FragmentTransaction替换方法: 根据Android文档, 替换添加到容器的现有片段。这与使用相同的containerViewId添加的所有当前添加的片段调用remove(Fragment),然后使用此处给出的相同参数添加(int,Fragment,String)基本相同。

假设案例1 :使用replace方法将删除当前(最后和最新)片段并在容器视图中添加新片段。

假设案例2 :使用replace方法将删除添加到同一容器视图中的片段。

但按照上述代码,上述情况似乎没有。

按照显示的代码点击按钮。 在每个按钮上单击直到count == 4,Fragment的新对象将被添加到容器中。

当我们点击按钮时,对于count == 5,这里使用replace方法,当时Fragment的新对象将被添加到容器中,onDestroyView方法被调用为第一个和第三个添加的片段

问题1:如果替换将删除在同一容器中添加的所有片段,那么为什么没有为第二个和第四个添加的片段调用onDestroyView?

问题2:如果替换方法删除了同一容器中的最后添加的片段,那么为什么它不会破坏第4个片段而是第1个和第3个片段?

根据我的理解,行为不符合Developer site上显示的文件。

如果我错了,请纠正我。

2 个答案:

答案 0 :(得分:2)

这似乎是replace方法的错误。 请注意,FragmentManager的支持版本不会发生这种情况。

我将参考thisthis

第一个标记为过时,第二个标记为已分配,但两者似乎都非常相关。

两者都突出显示,在for循环中删除片段(来自ArrayList),然后片段的ArrayList在此for循环内改变其大小,这会导致跳过一些索引,然后删除一些(不是全部)碎片。

这是链接中引用的for循环:

for (int i = 0; i < mManager.mAdded.size(); i++) {
    Fragment old = mManager.mAdded.get(i);
    // ... 
    if (f == null || old.mContainerId == f.mContainerId) {
        if (old == f) {
            op.fragment = f = null;
        } else {
            if (op.removed == null) {
                op.removed = new ArrayList<Fragment>();
            }
            op.removed.add(old);
            old.mNextAnim = op.exitAnim;
            if (mAddToBackStack) {
                old.mBackStackNesting += 1;
                if (FragmentManagerImpl.DEBUG) {
                    Log.v(TAG, "Bump nesting of "
                            + old + " to " + old.mBackStackNesting);
                }
            }
            mManager.removeFragment(old, mTransition, mTransitionStyle);
        }
    }
}

在您的具体情况下,您将添加片段1,2,3,4。之后,当您想要用第五个片段替换所有这四个片段时,执行上面的for循环。所以你删除了1st(对应于for循环中的i = 0),片段的arraylist变为2,3,4。然后你选择for循环中的下一个索引(i = 1),但同时arraylist改变了,所以取片段3(对应于i = 1)并删除它。最后,这个arraylist变为2,4和i = 2,并且没有片段对应于索引2.

我希望我能帮助你理解,即使我不拿50分:)

答案 1 :(得分:0)

for (int i=0; i<mManager.mAdded.size(); i++) {    
    Fragment old = mManager.mAdded.get(i);
    if (f ==null ||old.mContainerId == f.mContainerId) {
        mManager.removeFragment(old,mTransition, mTransitionStyle);
    }
}

MManager.mAdded是一个ArrayList列表,在遍历mManager.removeFragment方法时调用,该方法调用ArrayList remove方法;

Public void removeFragment (Fragmentfragment, int transition, inttransitionStyle) {
    MAdded.remove (fragment);    
}

这意味着在使用for循环

循环ArrayList列表时使用remove