My situation: I have two ListFragments (call them A and B) managed by one Activity which keeps persistent references to both of these Fragments. When I click a button in Fragment A, I replace that with Fragment B. The problem starts when I do the following flow.
A -> B -> (scroll) -> (back button) -> B
In that case, when I go back to Fragment B the second time, the previous scroll position is maintained, which I don't want. Instead, I would like for Fragment B to start with its ListView at the top of its content.
Things I have tried which do nothing:
Calling setSelection(0) in onActivityCreated
Calling setSelectionAfterHeaderViews() in onActivityCreated
Calling smoothScrollToPosition(0) in onActivityCreated
Interestingly, all of these work if I post them on a Runnable. However, when I do that there is a weird flickering the second time I open Fragment B.
So, how do I get Fragment B to automatically scroll to the top each time it is attached to its parent Activity? I feel like there must be something blindingly obvious that I'm missing, but I'm really stumped right now.
You're calling the right methods, but you're calling them in the wrong place.
I assume you have code that switches between the fragments and you call it when an item is clicked in A. So whenever you do the switch set the scroll to the top, something along these lines:
protected void switchList() {
ListFragment a = (ListFragment) getFragmentManager().findFragmentByTag("a");
ListFragment b = (ListFragment) getFragmentManager().findFragmentByTag("b");
b.getListView().setSelectionAfterHeaderView();
getFragmentManager().beginTransaction().hide(a).show(b).addToBackStack(null).commit();
}
And one important note: never keep persistent references to fragments in your activities. Whenever you need a fragment get it from the FragmentManager. This is crucial since on configuration change (like a device rotation, or when your app is suspended and restored) the fragments are recreated, and the reference you kept leads to a 'dead' fragment. Not only is it a major leak, it will also prevent your code from functioning. any change you make to the saved fragment is not reflected on the screen because the screen holds the newly created fragment.
Related
I have a Navigation panel activity. With 5 fragments (Will name it as Fragment1, Fragment2, ...) in menu sections.
Now by Default, activity will display Fragment1.
If user navigate to Fragmentxtz from Fragment1. We will add the fragment on top of Fragment1.
Now user goes to background by pressing home button and open the app from tasks.
Now i know Fragmentxtz onStart will be called. But i see that Fragment1 onStart is also called.
Is this expected behavior ?
As you can see on Android Developers, your fragment will be called at onViewCreated().
https://developer.android.com/guide/components/fragments#Creating
The View has to be updated in case you changed the system language or something like that.
Providing a bit more context to what might be happening here.
If both of your fragments are added e.g. via FragmentTransaction.add() both of them will have onCreateView() called when the layout is restored for the user as Robert pointed out. From the system's point of view all of those fragments are relevant to the user and would be shown simultaneously.
If on the other hand you add fragments via FragmentTransaction.replace() only the topmost fragment on the back stack will receive the onCreateView() call. This can also be achieved by doing an add and remove of the old fragment. If you make this transaction reversible by the back stack after pressing the back button your previous fragment would receive the appropriate lifecycle callbacks.
I have a view hierarchy such as below.
MainActivity :
FirstFragment :
SecondFragment :
In my SecondFragment, i have a RecyclerView. When an item is clicked, i want to open it in another Fragment (in full screen) so i am using the addSharedElement() method and everything works fine after 2 days of retro engineering it : every post i have found on StackOverFlow does not mention that in order to work, the "full-screen" fragment has to replace the first parent inside the activity.
What i first wanted was to nested the full-screen fragment inside the SecondFragment but it's impossible with this method.
I have tried everything else, at each steps of my view hierarchy & none of them is working, except if i replace my FirstFragment by my full-screen fragment.
This is also impossible to use the transition with the add() method unfortunately.
The problem is that this fragment is destroyed & not recreated despite the call of addToBackStack(), when i press the "back-button" inside the NavigationBar.
I am not really familiar with the addToBackStack() method & how can i get back any fragments i have added there.
QUESTION 1 : How can i make it work either without destroying the parent fragment (FirstFragment in my view hierarchy), or without using shared element transition but achieving the same result ?
It seems that what the Transition is doing is recreating a view in the new fragment with the same width / height, x & y coordinates as the one in the previous fragment & animate it from the new fragment...
QUESTION 2 : Would it be a bad idea to do it myself ?
EDIT : My goal is to close the full-screen fragment with a swipe down and as soon as the finger is moved from 10dp along the Y axis, i want to be able to reveal the previous fragment behind (the SecondFragment in my case), that's why i don't want to destroy parent fragments.
Scenario:
I have a fragment which has a ViewPager which contains 5 instances(different) of a single Fragment with different values, each having a listivew that contains some sort of items.
Problem:
The flow goes smooth when I click an item of listView(say on page1) but the moment I come back from there on pressing back (overridden OnBackPressed in the main_activity (will discuss later)), the viewPager fails to load the subFragments.
But when I switch to the 2nd or 3rd page, it gets displayed, and on going back to 1st page, it now gets displayed.
OnBackPressed():
I am maintaining a manual stack here. When I click on an item of ListView, the current Fragment Instance (of the parent Fragment ofcourse) goes into stack. And when user comes back , that instance gets popped off the stack and I replaces it on the activities FrameLayout container.
References:
Fragments not getting recreated by FragmentStatePagerAdapter after coming back to the main Fragment instance
Guys, I am really pissed off here, please help me out.
Frankly, I haven't worked much with fragments.
But it seems like the page is being thrown off the memory every time you switch to other pages. I am not sure but if there is a way for android to manage this and keep the page in its memory persistently, it might solve the problem
Finally I am able to get a workaround for this issue, which included two things:
while replacing the fragment make a call to
ft.replace(R.id.content_frame, frag).addToBackStack(null);
while initiating the ViewPager, the fragment manager to be used is :
mAdapter = new myAdapter(getChildFragmentManager());
Actually the problem is that, android fails to recognise and load the older instance of the fragment unless you explicitly add that instance to the backstack. So after adding it to BackStack, there is practically no need to maintain your own manual Stack, but you still can do that.
My application has a ViewPager whose adapter returns three Fragments.
Each Fragment loads a list of data from Web in the onCreateView.
So let's call these fragments A, B, C.
Once the activity containing the viewPager is open, Fragments A and B are loaded.
But only A is visible now.
So if I swipe to the right, then B is visible and C is loaded behind the scene.
If I swipe to right again, then C is visible.
The problem is that, fragment A's onDestroyView() is called and all its loaded data is gone!
So if I come back to fragment A, then A's onCreateView() is called again and A's data is loaded from the web again.
Is it a default behaviour of ViewPager when using it with Fragment?
Is it possible to keek the fragment alive (by not calling onDestroyView()) even while it is not visible?
Thanks
try:
yourViewPager.setOffscreenPageLimit(2)
where 2 is the amount of pages to keep in memory on either side of the current page.
I have a custom widget that performs FragmentTransaction.replace when buttons are pressed. Currently, my code is set up such that the first time a fragment is created, it attaches a bunch of stuff to the view that isn't originally part of the xml layout file.
When the app first launches, all my fragments show stuff correctly, however, let's say I start on Fragment A. I can then transition to Fragment B (with B showing up correctly), however, when I transition back to Fragment A, all the stuff I have attached to the view of Fragment A is now gone. I know this happens because onCreateView is called which probably means the Fragment's view is re-generated when FragmentTransaction.replace is called.
Is there a way where I can keep my fragments around instead of having them re-generate their views when FragmentTransaction.replace is called?
Thanks!
Instead of using fragmentTransaction.replace, use fragmentTransaction.show and fragmentTransaction.hide.
That will keep your fragments from being destroyed.