I am adding a fragment in an activity, fragment A.
Now from this fragment, I go to various other fragments, and whenever I go to those, I replace fragment A.
But there is only one scenario when i want that when i am about to go from fragment A to fragment Z, I add fragment A to the back stack.
So basically for all the clicks on fragment A, which take the user to other fragments (by replacing fragment A), there is only click where I want that fragment A be put in the back stack, this i want as when i press back from this new fragment Z, I do not want the activity to finish, rather i want fragment A to just come back up.
Now one dirty way of doing this is to do the following:
#Override
public void onBackPressed() {
if ( getFragmentManager().findFragmentByTag(FragmentZ.class.toString()) == null){
super.onBackPressed();
}
else {
//i would add fragment A over here.
}
}
But I was thinking that if i could add fragment A into the back stack just before i go to fragment Z then i do not have to take care of the above.
Could some please help me with the above?
The only way you can add Fragment A to the back stack is before you commit the transaction which replaces Fragment A with Fragment Z.
You can not add it later on after Fragment Z is already added.
Before calling commit() on the transaction which inserts Fragment Z, call addToBackStack(null) on the the transaction.
Then you will not have to override onBackPressed().
Related
I've implemented many fragments using the navigation graph. Consider I have A-> B-> C-> D
where A, B, C, D are the fragments in order of implementation. Now I am on fragment D and I want to move to fragment C on click of a button in D. How do I do that? Also when I reach fragment C and press the back button it should take me to fragment B. I want to implement navigation to the previous fragment and destroy the current fragment. i.e Move to C from D and destroy D(not want it on the press of a back button).
u can use below code you can get current position of your viewpager :
int position = mViewPager.getCurrentItem();
//or
Fragment fragment = adapter.getItem(position);
so also can use this code to dynamicity go which tab u want, so in button click listener set this code:
viewpager.setCurrentItem(specificFragmentPosition);
// like this: viewpager.setCurrentItem(2);
and for second question u have to override onBackPressed() method in your fragment
this method calls when user clicked in back button...
so u can add this code again in your onBackPressed() method,
viewpager.setCurrentItem(specificFragmentPosition);
I have an activity:
public class MainActivity extends FragmentActivity
{
private FragmentA a;
private FragmentB b;
private FragmentC c;
private HomeFragment mHomeFragment;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity_layout);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, mHomeFragment) // replace flContainer
.addToBackStack(null)
.commit();
...
}
I use some lazy initializer, and I keep my object a, b, c and mHomeFragment inside my activity object,
I have a button inside 'b' that calls the MainActivity to call 'c'
and a button inside 'c' that calls the MainActivity to call 'b'
and some other buttons to call 'a' which is not that important
Well now inside my FragmentB I have some custom views,
public CustomView(Context cnx, SettingsViewElement e, FragmentA fragment)
{
super(cnx);
inflate(cnx, R.layout.my_layout,this);
parent = fragment; // I use it later in my onCheckedChangeListener to tell him the the switch has been checked
condition = parent.getCondition();
titleTv = this.findViewById(R.id.title_tv);
switch = this.findViewById(R.id.switch);
if(condition){
switch.setChecked(true);
titleTv.setTitle("i am depressed af :(");
}
my question is :
why my switch doesn't turn checked even if my titleTv is updating the title ??
I did some tests and my OnCreated() is called each time I call replace() in my fragment transaction.
my fragment re-instantiate the views and then will add them to a linearLayout after inflating layout.
Also, if I don't keep my fragments reference in my MainActivity and then re-instantiate it every time.
here : the switch.setChecked will work ,
but the backStack will be huge and dumb
example: stack = 'b' -> 'c' -> 'b' -> 'c'
normally when the user click twice return button he'll be back to homeFragment, it doesn't need to empty the stack by itself.
and even if I override #onBackPressed() and re-instantiate the fragments each time hoping the android sdk will free the space.
I will have to do it manually each time I want to add a new fragment in my design, it will be a a wheel re-invention.
and : IT DOES NOT EXPLAIN WHY THE Switch.setChecked() doesn't work even if the condition is true and the other views are updating (textView is updating it's text)
Update : Apparently,
if the fragment is being re-used and the onCreate() is called for the
second time, (the reference for the fragment is being kept somewhere
and fragment is being attached for a second time) here the setChecked
will not take an effect, only some other view updates
meanwhile, it will only work if it's being called for the first time
the fragment is being created,
Solution : updating the views in the OnResume() method
If someone has an explanation for this, please go ahead
Update :
Apparently,
if the fragment is being re-used and the onCreate() is called for the seconde time, (the reference for the fragment is being kept somewhere and fragment is being attached for a seconde time)
here the setChecked will not take an effect, only some other view updates
meanwhile, it will only work if it's being called for the first time the fragment is being created,
Solution :
updating the views in the OnResume() methode
If someone has an explanation for this,
please go ahead
Views save and restore (some) of there state in the course of saveInstanceState/restoreInstance cycle, but unfortunatrly the checked state (and also visibility etc) are not covered by that.
So you'll have implement onSaveInstanceState etc. for your fragment and save/restore the checked state yourself.
EDIT
From your question it is not apparent what view switch actually is so I cannot give you actual code. But have a look at the implementation of CheckedTextView and check out the implementation of onSaveInstanceState() and onRestoreInstanceState(). You'll see that they save and restore the checked state (it's quite a lot of code with the SavedState class but in the end it is pretty simple). What you need to do, is to implement those two methods for your custom view (also creating your own SavedState inner class) and save/restore the checked state of your switch view.
A completely different and better approach would be to use a ViewModel for your fragment that holds the state, but that's a different story that would require lots of changes to your complete implementation.
Two days ago i asked the following question:
Change the fragment in a framelayout from within another fragment of said framelayout
A fellow user Krish, really helped me out in finding out what was wrong with the way i thought, but i am stil not sure how to actually get what i want done.
I want to be able to switch between three fragments in one FrameLayout.
- the first of the three is loaded at the start of the parent fragment and when back is pressed at the second fragment
- the second must be replacing the first at the click of an item in the listview of the first fragment, and when the back button is pressed from the third fragment
-the third must be loaded when a button is pressed in the second layout
I've tried achieving this by calling the following line whenever the fragment must be changed. A1_frame is the FrameLayout of the parent Fragment/Layout and A1_B0_C2 is the fragment i am replacing
getChildFragmentManager().beginTransaction().replace(R.id.A1_Frame, new A1_B0_C2()).addToBackStack(null).commit();
From what i understand the problem with my solution is that it isn't possible to replace a fragment in the FrameLayout of a parent Fragment/Layout, but if it would work, it would solve my solution. thats why i chose to put it in here.
I hope someone is able to tell me what would work!
getChildFragmentManager() returns the Fragment manager of the Fragment it's being called from, in this case whatever Fragment is in A1_Frame
The method you're looking for is getFragmentManager(), which returns the Fragment Manager of the Activity/Fragment that the Fragment is a part of. I.e. MainActivity, or whatever is creating your first fragment.
I have 3 activities which I want to convert into fragments so that I can implement a ViewPager to swipe between them:
Activity A ( to the left )
Activity B (central)
Activity C (to the right)
Activity B is called from an external activity and data is passed to it within the Intent. Now Activity B passes data within intents to Activities A and C when they are launched.The idea here is that B displays a slideshow with an ImageView which is updated every X seconds and A and C display information about the individual pictures. Hence, here are my questions:
How do I replicate this functionality with fragments so that when I swipe from Fragment B to C and from Fragment B to A I can pass the appropriate data to them. I currently do so this way with my activities:
Intent a = new Intent(SlideShow.this,MapsActivity.class);
a.putExtra("long", longitude);
a.putExtra("lang", langitude);
pauseSlideShow(i, timeRemaining);
isPaused = true;
startActivity(a)
I read up on the differences between FragmentPagerAdapter and FragmentStatePagerAdapter. Currently, when I launch activities A and C from B I do not call finish() on B so that when I return to it, it is in the exact same state as before. However, since activities A and C are supporting B, when I go back to activity B from A or C I end them by calling finish() on A and C respectively. How can I do this with fragments?
If you are using FragmentPagerAdapter, make sure that when you create a fragment in getItem() you save a reference to the fragment somewhere in the adapter or (preferably) the activity.
Create a method (i.e. getLatLong()) on fragment B that returns the data.
In fragment A in onCreateView(), you would get the reference to fragment B from the activity and call getLatLong() to get the data you need.
You can keep your fragments available in memory by calling viewpager.setOffscreenPageLimit(2). This way fragment A won't be destroyed when you swipe to fragment C, because the ViewPager will keep two fragments to the left of fragment C, which are your fragments A and B.
Another (probably better) approach is to create all three fragments at the beginning of the activity and return the appropriate fragment when getItem() is called. By doing this, you can use setTargetFragment() and getTargetFragment() to allow the fragments to get data from one another. When you do this, remember that a fragment may or may not have a UI available, so if you are pushing data rather than pulling, make sure the method receiving the data checks for getView() == null.
When adding activities to the stack, I can do something like this suggests:
How to bring an activity to foreground (top of stack)?
However, I have a Navigation Drawer that uses fragments. I add these fragments to my back stack via the below code:
FragmentTransaction transaction = activity.getFragmentManager().beginTransaction();
transaction.replace(R.id.main_fragment, new EntryFragment());
transaction.addToBackStack(activity.mTitle.toString());
transaction.commit();
The problem is, I now need to take a fragment that is already part of the back stack and bring it to the top, dropping all fragments currently above it out of the stack. Essentially what FLAG_ACTIVITY_REORDER_TO_FRONT and FLAG_ACTIVITY_CLEAR_TOP flags would do when using activities.
How do I accomplish this with fragments?
You can use the following method to return to the instance of the Fragment on the backstack:
activity.getFragmentManager().popBackStackImmediate(tag, 0);
Note, that in your FragmentTransaction you will need to define a unique tag for each Fragment you commit to the backstack and retrieve that tag to return to the fragment here.