Replacing a fragment with another fragment of the same class
I have a fragment
(let's call it MyFragment ) that inflates different layouts according to a parameter passed in the arguments.
All works well if MyFragment is started from a different fragment. But if MyFragment is active and I want to launch a new MyFragment with a different layout parameter, the fragmentManager
does not create a new fragment at all.
data.setInt("Layout index",i);
fragmentTab0 = (Fragment) new MyFragment();
fragmentTab0.setArguments(data);
fragmentTransaction.replace(R.id.fragmentContent, fragmentTab0, "MY");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
How can I force convince the fragmentTransaction
to launch the fragment again?
NOTE : The important point here is I need to inflate again a layout, which is different from the layout inflated before. The code looks like:
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;
}
Bypass Solution
Explanation (hoover to see it)
Since the source code for fragmentTransaction.replace/add/remove
is not available I could not find what really happens. But it is reasonable to think that at some point it compares the current class name with the replacement class name and it exits if they are the same.. Thanks to @devconsole for pointing out the source code. I know now why this happens. The FragmentManager.removeFragment()
method does not reset the fragment state, it remains RESUMED, then the method moveToState(CREATED)
only initilizes a fragment if (f.mState < newState)
= if (RESUMED < CREATED)
= false
. Else, ergo, it just resumes the fragment.
So to solve this problem I created an almost empty fragment which only purpose is to replace itself with the target fragment.
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();
}
}
And I use it:
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();
Now no fragment is replaced by a same class fragment:
MyFragment -> JumpFragment -> MyFragment
I haven't figured out how to pass the class through the arguments bundle, to make it totally generic.
The following worked without problems for me. Notice that I used the Android Support Library.
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;
}
}
}
Did you try to first remove your fragment with remove(fragMgr.findFragmentByTag("MY"))
and then add the new one ? PS : I assume you don't keep any reference to this fragment.
上一篇: 追踪int []的分配
下一篇: 用同一类的另一个片段替换片段