java - replace() 不适用于多 fragment

标签 java android android-fragments

主 Activity

package example.antonio.activitydemo;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.support.v4.app.*;

public class MainActivity extends FragmentActivity {

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

        final FragmentManager fragmentManager = getSupportFragmentManager();

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FirstFragment fragment = new FirstFragment();
                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

                fragmentTransaction.add(R.id.container, fragment);
                fragmentTransaction.commit();
            }
        });

        Button button2 = (Button) findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SecondFragment fragment = new SecondFragment();
                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

                fragmentTransaction.replace(R.id.container, fragment);
                fragmentTransaction.commit();
            }
        });
    }
}

第一 fragment

package example.antonio.activitydemo;

import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.view.View;

public class FirstFragment extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInsanceState) {
        return inflater.inflate(R.layout.first_fragment, container, false);
    }
}

第二个 fragment

package example.antonio.activitydemo;

import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.view.View;

public class SecondFragment extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInsanceState) {
        return inflater.inflate(R.layout.second_fragment, container, false);
    }
}

他们的 XML 文件:

ma​​in_activity.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:id="@+id/container"
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start1"
        android:id="@+id/button"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start2"
        android:id="@+id/button2"/>

</LinearLayout>

first_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#000000">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="First!"
        android:textColor="#ffffff"/>


</FrameLayout>

second_fragment.xml 与上一个一样,只是带有 android:text="Second!"

奇怪的是,当我点击 4 次 Start1 按钮时,我得到了 4 次单词 First!,直到这里一切正常。接下来,如果我单击 Start2 按钮,我会期望删除前面的 4 个 fragment 并添加一个新 fragment ,外观为 Second!。这是我从文档中了解到的:

Replace an existing fragment that was added to a container. This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.

但这是我得到的:

After I click 4 times <code>Start1</code> button After I click <code>Start2</code> button

我试着阅读源代码,也许我发现了“问题”在哪里,我想知道你的想法,如果是我,我在某个地方犯了错误。

这是 BackStackRecord.java 的 fragment ,run() 方法:

case OP_REPLACE: {
                    Fragment f = op.fragment;
                    int containerId = f.mContainerId;
                    if (mManager.mAdded != null) {
                        for (int i = 0; i < mManager.mAdded.size(); i++) {
                            Fragment old = mManager.mAdded.get(i);
                            if (FragmentManagerImpl.DEBUG) {
                                Log.v(TAG,
                                        "OP_REPLACE: adding=" + f + " old=" + old);
                            }
                            if (old.mContainerId == containerId) {
                                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);
                                }
                            }
                        }
                    }

这是 FragmentManager.java 的 fragment :

public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
        if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
        final boolean inactive = !fragment.isInBackStack();
        if (!fragment.mDetached || inactive) {
            if (false) {
                // Would be nice to catch a bad remove here, but we need
                // time to test this to make sure we aren't crashes cases
                // where it is not a problem.
                if (!mAdded.contains(fragment)) {
                    throw new IllegalStateException("Fragment not added: " + fragment);
                }
            }
            **if (mAdded != null) {
                mAdded.remove(fragment);
            }**
            if (fragment.mHasMenu && fragment.mMenuVisible) {
                mNeedMenuInvalidate = true;
            }
            fragment.mAdded = false;
            fragment.mRemoving = true;
            moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
                    transition, transitionStyle, false);
        }
    }

如您所见,removeFragment 方法从 mAdded 中删除了一个框架,但在 run() 方法之后, i 索引没有被修改,它从它离开的地方重新开始,这样它可能会丢失一些元素......

最佳答案

您无法使用线性布局作为容器来实现这种情况。

如果您尝试使用 fragment 作为线性布局中的容器,您可以实现这一点。请引用此链接以获取更多说明

Android - fragment .replace() doesn't replace content - puts it on top

否则使用下面的代码进行按钮点击操作,

Button button = (Button) findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            FirstFragment fragment = new FirstFragment();
            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();

            fragmentTransaction.add(R.id.container, fragment).addToBackStack(null);
            fragmentTransaction.commit();
        }
    });

    Button button2 = (Button) findViewById(R.id.button2);
    button2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            SecondFragment fragment = new SecondFragment();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            for(int i=0; i < getSupportFragmentManager().getBackStackEntryCount(); i++)
                getSupportFragmentManager().popBackStack();
            fragmentTransaction.replace(R.id.container, fragment);
            fragmentTransaction.commit();
        }
    });

希望这对你有帮助..谢谢

关于java - replace() 不适用于多 fragment ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33674527/

相关文章:

java - 如何获取在另一个字符串中找到的字符串的真实结束索引

java - 使用外部类锁获取内部类锁?

android - 发送短信后模拟器崩溃

Android布局: fragment with listview layout is not fullscreen

android - 如何将 Android activity_main.xml 中的这些 TextView 与 fragment 对齐?

java - Java lambda 可以有超过 1 个参数吗?

java - 获取 LIBGDX 中的光标位置

java - Android中如何根据动态SerializedName用gson解析json对象

java - 为什么排序方法不适用于此自定义 AbstractList 实现?

android - 通过更改 fragment 来更改工具栏,例如 instagram 应用程序