【问题标题】:Replacing a fragment with another fragment of the same class用同一类的另一个片段替换片段
【发布时间】:2013-06-18 20:23:50
【问题描述】:

我有一个 fragment(我们称之为 MyFragment),它根据参数中传递的参数扩展不同的布局。
如果 MyFragment 从不同的片段开始,则一切正常。但是,如果 MyFragment 处于活动状态并且我想使用不同的布局参数启动一个新的 MyFragmentfragmentManager 根本不会创建新的片段。

data.setInt("Layout index",i);
fragmentTab0 = (Fragment) new MyFragment();
fragmentTab0.setArguments(data);
fragmentTransaction.replace(R.id.fragmentContent, fragmentTab0, "MY");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

我如何强制说服fragmentTransaction再次启动片段?

注意:这里的重点是我需要再次膨胀一个布局,这与之前膨胀的布局不同。代码如下:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    switch( getArguments().getInt("Layout index") ) {
    case 1:
        rootView = inflater.inflate(R.layout.firstlayout, container, false);
        break;
    case 2:
        rootView = inflater.inflate(R.layout.secondlayout, container, false);
        break;
    case 3:
        rootView = inflater.inflate(R.layout.thirdlayout, container, false);
        break;
    default: break;
    }       

【问题讨论】:

  • @Waqas 我选的标题有误,我会改正的。我不是用它自己替换一个片段,我正在创建一个与当前片段相同类的新片段(你可以在我发布的代码中看到它)

标签: android android-fragments fragmenttransaction


【解决方案1】:

绕过解决方案
解释(胡佛看)

由于 fragmentTransaction.replace/add/remove 的源代码是 不可用 我找不到真正发生的事情。但它是 合理地认为在某些时候它会比较当前类 带有替换类名的名称,如果它们是 一样。。感谢@devconsole 指出来源 代码。我现在知道为什么会这样了。 FragmentManager.removeFragment() 方法不会重置片段状态,它保持 RESUMED,然后 moveToState(CREATED) 方法只初始化一个片段 if (f.mState < newState) = if (RESUMED &lt; CREATED) = false。否则,ergo,它只是恢复片段。

所以为了解决这个问题,我创建了一个几乎为空的片段,其唯一目的是用目标片段替换自己。

public class JumpFragment {

    public JumpFragment() {
    }

    @Override
    public void onStart() {
        Bundle data = getArguments();
        int containerId = data.getString("containerID");
        String tag = data.getString("tag");
        //Class<?> c = data.get???("class");            
        //Fragment f = (Fragment) c.newInstance();          
        Fragment f = (Fragment) new MyFragment();
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        f.setArguments(data);
        fragmentTransaction.replace(containerId, f, tag);
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
    }

}

我使用它:

data.setInt("Layout index",i);
data.setInt("containerID",R.id.fragmentContent);
data.setString("tag","MY");
fragmentTab0 = (Fragment) new JumpFragment();
fragmentTab0.setArguments(data);
fragmentTransaction.replace(R.id.fragmentContent, fragmentTab0);
fragmentTransaction.commit();

现在没有片段被相同的类片段替换:

我的片段 -> 跳转片段 -> 我的片段

我还没有弄清楚如何通过参数包传递类,以使其完全通用。

【讨论】:

  • 关于源代码:Class BackStackRecord extends FragmentTransaction.
  • @devconsole 我认为你搞错了。 BackstackRecord 扩展 FragmentTransaction。这不是FragmentTransaction 实现。
  • FragmentTransaction 是一个抽象类,BackStackRecord 扩展了该类,从而提供了一个实现。另见FragmentManager line 468FragmentManager.beginTransaction() 实际上返回一个BackStackRecord
  • @devconsole 谢谢,我找到了问题的原因并添加了解释。
  • 我仍然无法在运行 Android 4.2.2 的 Nexus 4 上重现该问题。我尝试了本机 API 和 Android 支持库,我的示例在这两种情况下都适用,请参阅我的答案。也许问题已在
【解决方案2】:

以下对我来说没有问题。请注意,我使用了 Android 支持库。

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/button_one"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ONE" />

    <Button
        android:id="@+id/button_two"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/button_one"
        android:text="TWO" />

    <FrameLayout
        android:id="@+id/main_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/button_one" >
    </FrameLayout>

</RelativeLayout>

MainActivity.java:

public class MainActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction transaction = fragmentManager.beginTransaction();
            Fragment fragment = DetailsFragment.newInstance("INITIAL");
            transaction.add(R.id.main_container, fragment);
            transaction.commit();
        }

        findViewById(R.id.button_one).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                update("Button 1 clicked");
            }
        });

        findViewById(R.id.button_two).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                update("Button 2 clicked");
            }
        });
    }

    protected void update(String value) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        Fragment fragment = DetailsFragment.newInstance(value);
        transaction.replace(R.id.main_container, fragment);
        transaction.commit();
    }

    public static final class DetailsFragment extends Fragment {
        public static DetailsFragment newInstance(String param) {
            DetailsFragment fragment = new DetailsFragment();
            Bundle args = new Bundle();
            args.putString("param", param);
            fragment.setArguments(args);
            return fragment;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            TextView textView = new TextView(container.getContext());
            textView.setText(getArguments().getString("param"));
            return textView;
        }
    }
}

【讨论】:

    【解决方案3】:

    您是否尝试先使用remove(fragMgr.findFragmentByTag("MY")) 删除您的片段,然后添加新片段? PS:我假设你没有保留对这个片段的任何引用。

    【讨论】:

    • 我使用了replace,根据文档: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.
    • 是的,这应该可以解决问题...试试remove 也许实现有点不同。
    • 我尝试将 replace 拆分为 remove + add,但仍然是相同的行为
    【解决方案4】:

    如果我对您的理解正确:您要替换当前显示的片段并且用户执行了某些操作以使其重新显示?

    如果这是正确的,那么已经用这种方式做了类似的事情:

     public class MyFragment extends Fragment {
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                // Inflate the layout for this fragment
                final View V = inflater.inflate(R.layout.myLayout, container, false);
    
                // Call method that fills the layout with data
                displayData(V);
    
                // Put a listener here that checks for user input
                Button redisplayButton = (Button) V.findViewById(R.id.my_button);
                    // if the button is clicked....
                   redisplayButton.setOnClickListener(new OnClickListener() {
                        public void onClick(View v){
                        //
                        //  do some stuff
                        //
                        //  ....then eventually...
                        displayData(V); 
                    }
                  });
    
            return V;
            }
    

    稍后您可以使用 displayData() 方法来定义片段显示的内容....

        public void displayData(View V){
    
           //  Do something
    
    
        return;
        }
    

    希望这会有所帮助!

    【讨论】:

    • 不完全是我需要的。正如我所写,我根据片段数据包上传递的参数膨胀不同的布局。你的例子只膨胀一次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-18
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-12
    相关资源
    最近更新 更多