Android replace the current fragment with another fragment - android

I just started with fragment design for HoneyComb. I created two fragments. When i click a button in the left side fragment, a new fragment is created in right side. Meanwhile when i click a button in the right fragment(ie. DetialsFragment in my code below should be replaced by another fragment.
main.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:orientation="horizontal" >
<fragment class="com.fragment.example.Titles"
android:id="#+id/titles" android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
<FrameLayout android:id="#+id/details" android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
</LinearLayout>
FragmentExample.java
public class FragmentExample extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Titles.java
public class Titles extends Fragment {
public FragmentTransaction ft;
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.main1, null);
Button button1 = (Button)v.findViewById(R.id.button1);
button1.setText("santhosh");
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != 1) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(1);
// Execute a transaction, replacing any existing
// fragment with this one inside the frame.
ft
= getFragmentManager().beginTransaction();
ft.add(R.id.details, details, "detail");
ft.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
}
});
return v;
}
}
DetailsFragment.java
public class DetailsFragment extends Fragment {
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
Titles title = new Titles();
String[] titles = {"Title1", "Title2", "Title3", "Title4"};
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
// Currently in a layout without a container, so no
// reason to create our view.
return null;
}
Button button = new Button(getActivity());
button.setText("Next");
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
return button;
}
}

Then provided your button is showing and the click event is being fired you can call the following in your click event:
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, new NewFragmentToReplace(), "NewFragmentTag");
ft.commit();
and if you want to go back to the DetailsFragment on clicking back ensure you add the above transaction to the back stack, i.e.
ft.addToBackStack(null);
Or am I missing something? Alternatively some people suggest that your activity gets the click event for the button and it has responsibility for replacing the fragments in your details pane.

Latest Stuff
Okay. So this is a very old question and has great answers from that time. But a lot has changed since then.
Now, in 2020, if you are working with Kotlin and want to change the fragment then you can do the following.
Add Kotlin extension for Fragments to your project.
In your app level build.gradle file add the following,
dependencies {
def fragment_version = "1.2.5"
// Kotlin
implementation "androidx.fragment:fragment-ktx:$fragment_version"
// Testing Fragments in Isolation
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
}
Then simple code to replace the fragment,
In your activity
supportFragmentManager.commit {
replace(R.id.frame_layout, YourFragment.newInstance(), "Your_TAG")
addToBackStack(null)
}
References
Check latest version of Fragment extension
More on Fragments

You can try below code. it’s very easy method for push new fragment from old fragment.
private int mContainerId;
private FragmentTransaction fragmentTransaction;
private FragmentManager fragmentManager;
private final static String TAG = "DashBoardActivity";
public void replaceFragment(Fragment fragment, String TAG) {
try {
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(mContainerId, fragment, tag);
fragmentTransaction.addToBackStack(tag);
fragmentTransaction.commitAllowingStateLoss();
} catch (Exception e) {
// TODO: handle exception
}
}

Use android.support.v4.app for FragmentManager & FragmentTransaction in your code, it has worked for me.
DetailsFragment detailsFragment = new DetailsFragment();
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.details,detailsFragment);
fragmentTransaction.commit();

If you have a handle to an existing fragment you can just replace it with the fragment's ID.
Example in Kotlin:
fun aTestFuction() {
val existingFragment = MyExistingFragment() //Get it from somewhere, this is a dirty example
val newFragment = MyNewFragment()
replaceFragment(existingFragment, newFragment, "myTag")
}
fun replaceFragment(existing: Fragment, new: Fragment, tag: String? = null) {
supportFragmentManager.beginTransaction().replace(existing.id, new, tag).commit()
}

Updated Answer (Working for Overlap problem as well)
#aniket-thakur(https://stackoverflow.com/users/2396539/aniket-thakur) gave correct answer. Thank you for that!
But, getFragmentManager() is deprecated, so following code did work for me.
final FragmentTransaction ft = getParentFragmentManager().beginTransaction();
ft.replace(R.id.nav_host_fragment, new GalleryFragment(), "NewFragmentTag");
ft.addToBackStack(null);
ft.commit();

it's very simple how to replace with Fragment.
DataFromDb changeActivity = new DataFromDb();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.changeFrg, changeActivity);
transaction.commit();

Related

View Issue Calling SecondFragment from FirstFragment

I am making a simple demo project using Fragments, in which i am calling SecondFragment from FirstFragment on button click.
And i called SecondFragment without any issue, but i getting view of both the Fragments SecondFragment and FirstFragment
So where i am doing mistake ?
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new FirstFragment()).commit();
}
}
public static class FirstFragment extends Fragment {
Button buttonCallSecondFragment;
public FirstFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_first, container,
false);
buttonCallSecondFragment = (Button) rootView.findViewById(R.id.button1);
buttonCallSecondFragment.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
FragmentManager fm = getFragmentManager();
SecondFragment fragment = new SecondFragment();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.container, fragment);
ft.commit();
}
});
return rootView;
}
}
public static class SecondFragment extends Fragment {
public SecondFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_second, container,
false);
return rootView;
}
}
}
You need to remove the first fragment, you can do that either by usingreplace or first calling remove then add
To be able to press the back button add the transaction to the back stack,you do that by calling addToBackStack(tag) on your fragment manager. Tag may be null.
You are adding fragment on already displaying fragment in your android app.
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.container, fragment);
ft.commit();
Do not add fragment but replace fragment when already one fragment is loaded on activity.
So for implementing that :
Please add your code in OnCreate() and add below code to your click listener :
FragmentManager fm = getFragmentManager();
SecondFragment fragment = new SecondFragment();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.container, fragment);
ft.addToBackStack(null);
ft.commit();
Thank you.!!
if you want to replace fragment you should call replace in place of add :
buttonCallSecondFragment = (Button) rootView.findViewById(R.id.button1);
buttonCallSecondFragment.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
FragmentManager fm = getFragmentManager();
SecondFragment fragment = new SecondFragment();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.container, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
}
});
You are adding the fragment so it will come on top of another fragment give background color to rootview of scecond fragment
you can also load that as Nested fragment
public void addFragB() {
FragmentManager childFragMan = getChildFragmentManager();
FragmentTransaction childFragTrans = childFragMan.beginTransaction();
SecondFragment 2ndfrag = new SecondFragment();
childFragTrans.add(R.id.fragA_LinearLayout, 2ndfrag);
//childFragTrans.addToBackStack("");
childFragTrans.commit();
}
No, you cannot communicate between fragments like this. You need to communicate between fragments via the container activity.
I suggest, you make a navigation method in your activity and switch/call between fragments from there.
Below is a small snippet:
In your container activity:
Fragment fragment;
public void navigateTo(Fragment newFragment,boolean addToBackStack) {
this.fragment = newFragment;
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.fragment_container, newFragment);
if(addToBackStack)
ft.addToBackStack(fragment.getClass().getSimpleName());
ft.commit();
}
If you are going from Fragment1 to Fragment2 then in your Fragment1 do the following:
((YourContainerActivity) getActivity()).navigateTo(new Fragment2(),false); //if you want to add to back stack make 2nd argument true.
private void selectItem(int position) {
selectedPosition = position;
// update the main content by replacing fragments
fragment = null;
fragmentStack = new Stack<Fragment>();
switch (position) {
case 0:
fragment = new Fragment1();
break;
case 1:
fragment = new Fragment2();
break;
}
//redirect the screen
if (fragment != null) {
fragmentManager = getSupportFragmentManager();
redirectScreen(fragment);
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(title[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
}

Saving Fragment State/Data from Fragment to Fragment

I'm trying to figure out how to save user inputted data on a fragment if they leave it and come back. I have one Activity that several Fragments work off of. All the examples I find are saving the state when leaving the Fragment and Activity. I'm never leaving the Activity; therefore onSaveInstanceState within the Fragment is never called. onPause is called, but I'm unable to figure out how to save the state within there.
This app displays a list of tickets. When the user taps a ticket, it grabs preliminary information from the local DB for read only fields and allows the user to input the ticket information before submitting. I'm trying to allow a user to tap on a ticket, enter data, leave and come back to that ticket without losing information entered.
Out of all the examples I've studied on this, it seems to me I can use Fragmenttransaction to save the Fragment's ID. Below is the main Activity that all fragments are attached to:
public class Activity_Main extends Activity
implements Fragment_OpenTickets.INT_OnOpenTicketSelectedListener,
Fragment_SubTickets.INT_OnSubTicketSelectedListener,
Fragment_Ticket.INT_SubmitNewTicket {
DBController dbc;
Fragment fr;
boolean gps_enabled = false;
boolean network_enabled = false;
HashMap<String, String> addInfo;
RadioButton btn_radio_open;
RadioButton btn_radio_submitted;
RadioButton btn_radio_settings;
String ticketDate, ticketTime;
int m, d, y, hr, min;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_radio_open = (RadioButton)findViewById(R.id.radio_open);
btn_radio_submitted = (RadioButton)findViewById(R.id.radio_submitted);
btn_radio_settings = (RadioButton)findViewById(R.id.radio_settings);
dbc = new DBController(this);
if (dbc.checkCredentials() != null) {
fr = new Fragment_OpenTickets();
} else {
fr = new Fragment_Settings();
btn_radio_open.setChecked(false);
btn_radio_submitted.setChecked(false);
btn_radio_settings.setChecked(true);
}
FragmentManager fm = getFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_place, fr);
ft.addToBackStack(null); // For back button action.
ft.commit();
// Start scheduler service.
this.startService(new Intent(this, Service_Send.class));
// Start GPS service.
startGPS();
}
/**
* Top menu buttons.
*/
public void selectFrag(View view) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
switch (view.getId()) {
case R.id.radio_open:
//fr = new Fragment_OpenTickets();
ft.replace(R.id.fragment_place, new Fragment_OpenTickets());
ft.addToBackStack(null);
btn_radio_submitted.setChecked(false);
btn_radio_settings.setChecked(false);
ft.commit();
break;
case R.id.radio_submitted:
//fr = new Fragment_SubTickets();
ft.replace(R.id.fragment_place, new Fragment_SubTickets());
ft.addToBackStack(null);
btn_radio_open.setChecked(false);
btn_radio_settings.setChecked(false);
ft.commit();
break;
case R.id.radio_settings:
//fr = new Fragment_Settings();
ft.replace(R.id.fragment_place, new Fragment_Settings());
ft.addToBackStack(null);
btn_radio_open.setChecked(false);
btn_radio_submitted.setChecked(false);
ft.commit();
break;
}
}
/**
* Open ticket selection action.
*/
public void onOpenTicketSelected(HashMap position) {
// Create fragment and give it an argument for the selected ticket.
fr = new Fragment_Ticket();
Bundle args = new Bundle();
args.putSerializable("HashMap", position);
fr.setArguments(args);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_place, fr);
ft.addToBackStack(null); // For back button action.
ft.commit();
}
/**
* Submitted ticket selection action.
*/
public void onSubTicketSelected(HashMap position) {
// Create fragment and give it an argument for the selected ticket.
fr = new Fragment_SubTicket();
Bundle args = new Bundle();
args.putSerializable("HashMap", position);
fr.setArguments(args);
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fr);
fragmentTransaction.addToBackStack(null); // For back button action.
fragmentTransaction.commit();
}
Any help will be very appreciated. If I need to post more code then please let me know. Thank you!
I think you should store ticket info in your Activity when users leave the fragment and get the info back and display it when you come back.
In Activity_Main class, you create 2 methods:
public void saveTicketInfo(TicketInfo info) {
// save info here
}
And:
public TicketInfo getTicketInfo() {
// get info here
}
In your fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
// get ticket info and display it
Activity_Main mainActivity = (Activity_Main)getActivity();
TicketInfo info = mainActivity.getTicketInfo();
if (info != null) {
// handle display info here
}
...
}
#Override
public void onDestroyView() {
TicketInfo info = new TicketInfo();
// get info from view and store in the object
Activity_Main mainActivity = (Activity_Main)getActivity();
mainActivity.saveTicketInfo(info)
super.onDestroyView();
}
I posted a lengthy detailed answer on SO # Passing data between fragments contained in an activity. Search for my answer on it. This is a safe way to pass data from Fragment to Activity. And then you can easily pass that data from Activity to the Fragment's constructor or public method.

Add Fragment on another fragment

I want to achieve below concept in android:-
Tab A -> Fragment A -> Fragment 1 -> Fragment 2
Tab B -> Fragment B
Tab C -> Fragment C
Tab D -> Fragment D
I am adding tabs on view pager and able to achieve till
Tab A -> Fragment A
Tab B -> Fragment B
Tab C -> Fragment C
Tab D -> Fragment D
I tried with
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(android.R.id.content, fragment1);
ft.addToBackStack(null);
ft.commit();
but not able to add another fragment on Fragment A.
it is adding fragment 1 upon Fragment A but Fragment A is still visible in background. So please provide some suggestion to achieve above task.
Thanks in Advance.
It's mine. Hope it's helpful.
First, you need to create the ContentFragment for 4 tabs A, B, C, D like below:
public class ContentFragmentA extends BaseFragment {
private static Context context;
#SuppressWarnings("static-access")
public ContentFragmentA(Context context) {
super();
this.context = context;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.content_frame_a, container, false);
this.setFragmentManager(getChildFragmentManager());
this.setContainerId(R.id.content_frame_a);
this.replaceFragmentIntoStack(new FragmentOne(context), "FragmentOne");
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}}
Then, create the content_fragment_a.xml file
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/content_frame_a"
android:layout_width="match_parent"
android:layout_height="match_parent" >
Then, for each new fragment you should extends BaseFragment. And when if you want to put new fragment into tab, just use addFragmentIntoStack(), or replaceFragmentIntoStack().
public class BaseFragment extends Fragment{
private FragmentManager fragmentManager;
private int containerId;
private boolean doubleBackToExit = false;
/**
* #param containerId the containerId to set
*/
public void setContainerId(int containerId) {
this.containerId = containerId;
}
/**
* #param fragmentManager the fragmentManager to set
*/
public void setFragmentManager(FragmentManager fragmentManager) {
this.fragmentManager = fragmentManager;
}
/**
*
*/
public BaseFragment() {
super();
// TODO Auto-generated constructor stub
BarddyApplication.getInstance().baseFragment = BaseFragment.this;
}
public void addFragmentIntoStack(BaseFragment newContent, String tagName) {
newContent.setFragmentManager(fragmentManager);
newContent.setContainerId(containerId);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(containerId, newContent, tagName);
fragmentTransaction.addToBackStack(tagName);
fragmentTransaction.commitAllowingStateLoss();
}
public void popFragment() {
fragmentManager.popBackStack();
}
public void replaceFragmentIntoStack(BaseFragment newContent, String tagName) {
newContent.setFragmentManager(fragmentManager);
newContent.setContainerId(containerId);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(containerId,newContent,tagName);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commitAllowingStateLoss();
}}
Very simple!
Fist you need to fragment A blank and then you need create new three fragment:
Fragment A1, fragment 1, fragmen2
And now when you chose tab A, you show fragment A1 in fragment A
FragmentTransaction transaction = getFragmentManager()
.beginTransaction();
transaction.replace(R.id.category_fragment, new CategoryFragment());
transaction.commit();
Now you can use method replace() fragment 1 or 2 to id of Fragment A (not id of A1) to replace A1 with fragment 1 or 2.
Hope it help you!

How to provide back button in fragments programmatically?

I have one Activity with two fragments.here i provide one back button in 2nd fragment programatically to goback to 1st fragment.
here my fragment1 code:
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
V = inflater.inflate(R.layout.lm_fragement, container, false);
listview = (ListView)V.findViewById(R.id.listView1);
url="http://victorysites.org/apps/SSPC/homeinfo.php?UDID=12341234";
JsonParsing json=new JsonParsing();
list=json.getData(url);
System.out.println("length :"+list.size());
listview.setAdapter(new MyAdapter(getActivity(),list));
final ProgressDialog waitdialog;
listview.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
Bundle data = new Bundle();
data.putString("name",""+arg2);
Fragment f;
f = new PM_Fragment();
f.setArguments(data);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(android.R.id.content, f);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
});
Button bt=(Button)V.findViewById(R.id.button1);
bt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Bundle data = new Bundle();
data.putString("name","Venkat");
Fragment f;
f = new PM_Fragment();
f.setArguments(data);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(android.R.id.content, f);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
});
return V;
}
}
Here my fragment2 code:
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
f=new PM_Fragment();
V = inflater.inflate(R.layout.pm_fragment, container, false);
Bundle bundle = this.getArguments();
String myInt = bundle.getString("name");
System.out.println("NAME"+myInt);
TextView tv=(TextView)V.findViewById(R.id.portrait_message);
tv.setText(myInt);
Button bt=(Button)V.findViewById(R.id.button1);
bt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
/*Fragment f=new PM_Fragment();
getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit();*/
//getActivity().getFragmentManager().beginTransaction().remove(this).commit();
getFragmentManager().popBackStack();
}
});
return V;
}
}
its working fine,but the problem is it reloads the previous(1st fragment) screen.But i don't want reload the page,i want its working like default back button in emulator.
Anyone can give me an idea. Thanks in advance.
When using fragments in your app, individual FragmentTransaction objects may represent context changes that should be added to the back stack. If you are implementing a master/detail flow on a handset by swapping out fragments, you should ensure that pressing the Back button on a detail screen returns the user to the master screen. To do so, call addToBackStack() before you commit the transaction:
// Works with either the framework FragmentManager or the
// support package FragmentManager (getSupportFragmentManager).
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail")
// Add this transaction to the back stack
.addToBackStack()
.commit();
*When there are FragmentTransaction objects on the back stack and the user presses the Back button, the FragmentManager pops the most recent transaction off the back stack and performs the reverse action (such as removing a fragment if the transaction added it).*
Note: You should not add transactions to the back stack when the transaction is for horizontal navigation (such as when switching tabs) or when modifying the content appearance (such as when adjusting filters). For more information, about when Back navigation is appropriate, see the Navigation design guide.
ADDED
If your application updates other user interface elements to reflect the current state of your fragments, such as the action bar, remember to update the UI when you commit the transaction. You should update your user interface after the back stack changes in addition to when you commit the transaction. You can listen for when a FragmentTransaction is reverted by setting up an FragmentManager.OnBackStackChangedListener:
getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
// Update your UI here.
}
});
Please refer this link for more details

Fragments Behave Weirdly When Using addToBackStack()

An SSCCE for this issue is available on GitHub.
For future readers, the original example is on a branch of the same project, and the fix is available in this diff.
This SSCCE has a ListView and a row of buttons. The buttons are supposed to change the data in the ListView, and the listView rows (when clicked) are supposed to open a new fragment and advance the backstack while staying in the same activity.
If do the following things, it produces the following result:
Open the app.
Tap the ListView. - FragmentTransaction.replace(...) with addToBackStack(true)
Tap any of the buttons. - FragmentTransaction.replace(...) with addToBackStack(false)
Tap the back button.
Result:
Both fragments become visible, but I only want the first loaded fragment (ListTwoFragment in code) to display. Is this how fragments are supposed to work? If so, how can I get the desired effect?
MainActivity.java:
public class MainActivity extends FragmentActivity implements ListTwoFragment.Callbacks,
ListThreeFragment.Callbacks {
public static final String KEY_ARGS = "args";
private String curUri = "";
private String curArgs = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
selectContent(false);
}
private void selectContent(boolean addToBackStack) {
Fragment fragment;
if (curUri.isEmpty()) {
// Use default fragment
fragment = new ListTwoFragment();
curUri = ListTwoFragment.class.getName();
}
else {
try {
Class<Fragment> fragmentClass = (Class<Fragment>) Class.forName(curUri);
fragment = fragmentClass.newInstance();
}
catch (Exception e) { // ClassNotFound, IllegalAccess, etc.
return;
}
}
// Configure fragment
Bundle args = new Bundle();
args.putString(KEY_ARGS, curArgs);
fragment.setArguments(args);
attachFragment(fragment, addToBackStack, curUri + ";" + curArgs, R.id.fragment_container);
}
protected void attachFragment(Fragment fragment, boolean addToBackStack, String tag, int replaceId) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(replaceId, fragment, tag);
if (addToBackStack) transaction.addToBackStack(tag);
transaction.commit();
}
#Override
public void onTwoButtonClick(String title) {
curUri = ListTwoFragment.class.getName();
curArgs = title;
selectContent(false);
}
#Override
public void onTwoListClick() {
curUri = ListThreeFragment.class.getName();
curArgs = "";
selectContent(true);
}
#Override
public void onThreeButtonClick(String title) {
curUri = ListThreeFragment.class.getName();
curArgs = title;
selectContent(false);
}
}
I'm working with Fragments to, and the way I'm doing it:
to go forward (add to stack), and backwords (remove from stack) are two different functions
to Add to Stack and change Fragment:
public void changeFragmentAddToStack(Fragment myNewFragment) {
FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.add(R.id.main_fragment, myNewFragment);
t.addToBackStack(null);
t.commit();
}
To go back Stack:
public void goBackStackMain() {
FragmentManager man = getSupportFragmentManager();
if(man.getBackStackEntryCount()>0){
man.popBackStack(man.getBackStackEntryAt(0).getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
And if you want to do both: To go back stack and change fragment:
public void goBackStackAndReplaceFragment(Fragment myNewFragment) {
FragmentManager man = getSupportFragmentManager();
if(man.getBackStackEntryCount()>0){
int n = man.getBackStackEntryCount();
man.popBackStack(man.getBackStackEntryAt(n-1).getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.replace(R.id.main_fragment, myNewFragment);
t.commit();
}
I hope to help you !

Categories

Resources