Managing Action Bar titles when using fragments and the backstack - android

My app has an activity which uses the FragmentManager to push and pop fragments onto the backstack. However, when the backstack has 2 fragments and the last fragment is popped, I do not how to detect this to set the title of the Action Bar appropriately. I was hoping there was some method on a fragment I could override to determine when it becomes visible, but none of those suggested e.g. uservisiblehint, onHiddenChanged, etc. are called. How can I either:
• determine when a fragment becomes visible; OR
• effectively manage action bar titles when using fragments on a backstack?

You can add a addOnBackStackChangedListener which will get called every time back stack changes.
Inside this function you can simply get the topmost fragment and call onResume for it.
For more information you can refer to following link:
Fragments onResume from back stack

Related

Navigation Component not calling onDestroy for bottom nav fragments

It might be my misunderstanding of this libary itself, but I seem to be running into an issue. I am currently using Android Navigation Component (v3.4.0) and I am using a bottom navigation bar, which are linked together.
The issue I am see is that when I navigate to another bottom navigation item, a new fragment is created and a new viewmodel. None of the previous instances are destroyed, or at least onDestroy is not being called. I can test the logic by consuming a flow, when I navigate from bottom nav item 1, to bottom nav item 2, then back to bottom nav item 1, and emitted items from the flow are received twice, as there are now 2 instances of bottom nav item 1s view model. I can also log the hashcodes of each instance and see there's a difference.
When I navigate up a level, and back, the higher level fragment and viewmodel have their onDestroy and onCleared called.
Am I misunderstanding how this library is supposed to work?

What will be fragment behavior when came from background. Considering fragment is in stack

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.

Clear backstack and replace current fragment with a top-level fragment

I have one activity in my android app which handles the replacement of multiple views/fragments. This activity also has a navigation drawer to navigate to top-level fragments. From the top-level fragments you can navigate to detail-level fragments.
The navigation drawer can always be accessed by sliding it in from the left side. If the current fragment is a top-level fragment, the navigation-drawer can also be accessed by the action-bar. If the current fragment is a detail-level fragment, you can navigate back through the action-bar (or by pressing the back-button).
Lets say I have 3 top-level fragments which can be accessed through the navigation drawer.
fragment[1], fragment[2], fragment[3]
From fragment[1], you can navigate to the detail-level fragment[1.1].
Now the user wants to navigate directly to the top-level fragment[3] from the current fragment[1.1]. The user just has to slide in the navigation-drawer and click the item for fragment[3].
Now, if the user hits the back button, the application should close (because it navigated to a top-level fragment). So every time the user navigates to a top-level fragment, the backstack should be cleared. To check if I should display the drawer indicator, I am reading the getBackStackEntryCount()-value and compare it with 0.
As a summary. I want to navigate from detail-level fragments to any top-level fragments and clear the backstack.
The problem:
When I clear the backstack by executing
getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);,
the fragment transactions are replayed in reverse (for example the replacement of fragment[1] by fragment[1.1]). And I DON'T want them to be replayed. I have a lot of initializations in onCreateView, onViewCreated, onStart, .., also starting tasks to fetch data. And I want to skip that all. Just replace the detail level view with a new top-level one which wasn't already in the backstack.
I couldn't find any solution to clear the backstack without popping transactions.
Is there a clean solution to handle this problem? Do I have to implement my own backstack-behavior?
EDIT:
The YouTube app also behaves like this. When you navigate from detail to top-level, the backstack gets cleared. But how do they clear the backstack without replaying the fragment-transactions?
Thanks for your answers.
I think you problem is that you are popping fragments in a loop - I guess. I usually push fragments on the fragment stack together with specifying custom animations - say slide in new fragment from the right and when popping it our slid out to the right. Now - if your user has navigated to fragment 1 then 1.1 then 1.2 etc and you want to navigate back to 1 when a user clicks the home button in the action bar - specify a name for you fragment 1 transaction. The you you perform popping use that name. Also consider using popBackStack function instead of popBackStackImmediate.

Android Navigation Drawer with many fragments

I've been struggling with this for a while now, I want to start off with a diagram of my problem:
The three navigation drawer buttons are part of my Base Activity. Each purple block below the three buttons are fragments, and the descendants of each of those blocks are in turn fragments. I'll use the master and detail fragments as a demonstration of the issue I am having...The user clicks the nav drawer button, which opens the master fragment that hosts a list of articles. Once a user clicks one of those articles, I then open the detail fragment inside of the master fragment. So If I find myself at the detail, and I decide to open the nav drawer and click the third button for instance, then click the second button again, I want the detail to be open still, and if I hit the phone's back button I want it to move back to the master fragment, and end there. Any tips will be helpful, as I am probably going to use a similar pattern for the first button, it's main fragment and it's children fragments as well.
In my opinion, the cleanest way to handle what you are describing would be to have three separate FragmentActivity classes that implement the DrawerLayout instead of one monolithic BaseActivity.
Each button in the drawer should start it's respective FragmentActivity using launchMode singleTask. This ensures that you launch the same activity instance each time, instead of a new one, which will maintain your back stack for each activity as you switch between them using the drawer buttons. See Android Developer Guide Activity:launchMode for more details.
Each of the three FragmentActivity instances should be responsible for starting and managing it's fragments using listener interfaces. For example, where you have your Master fragment opening a Detail fragment directly, you should instead have your Master fragment tell it's FragmentActivity that it needs to open the Detail fragment. See Android Developer Guide: Communicating with Other Fragments for recommended practices in implementing this type of decoupled communication between FragmentActivity and Fragment. It will make your life much easier down the road when you want different layouts for tablets, etc.
Each of the three main drawer "tasks" seem to be unique enough that isolating each within it's own FragmentActivity seems the best way to implement what you are trying to do. You can apply this same approach for each of your main sections.
I had the same problem and didn't want to go to multiple activities since that would complicate the back navigation of my application. Your fragments won't save their state automatically unless the activity lifecycle events are being called.
In our case those don't happen since we're not leaving the activity. You can use FragmentManager's saveFragmentState on the fragment you are replacing to manually trigger the state saving and get a Fragment.SavedState object. You can keep a list of your SavedState objects and when pushing a fragment check if you have a saved state for it. If so you can call Fragment setInitialSavedState which will cause your fragment to load the previous state.
Now in my app as a user toggles between fragments with their own child fragments the state is retained when they come back.

Android changing setNavigationMode per fragment is crashing the app

I created the below project so you can see my exact code and what is going on:
https://github.com/CorradoDev/TabsTest/commit/8f054dab2371b791c4061ceb511413f720f65d67
Basically what I am trying to do is hide the tabs for some pages and show them in other pages.
Below is the code I am using to show the tabs in the onresume
if(getActivity().getActionBar().getNavigationMode()==ActionBar.NAVIGATION_MODE_STANDARD){
getActivity().getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
}
THen to hide the tabs I am doing the below on resume:
getActivity().getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
When I am on the first fragment(nothing in backstack). I can show and hide the tabs on hte second. It gives errors sometimes with changing tabs.
When I am on the second fragment in the backstack and I hide the third fragment. I see the second and third fragment both call the onrefresh but the third fragment does not show.
I am confused on what is going on and why this is not easier.
Below is the error I generally get
03-27 15:26:31.029: E/AndroidRuntime(5505): java.lang.IllegalStateException: Fragment already added: Fragment3{41f2e390 #2 id=0x1020002 fragment3}
I still would like to know why the above does not work. But my fix was to create another activity with the fragment and no tabs. That seems to work well. But I am interested if they did not intend you to change tabs and no tabs per fragment.
I had a similar situation - only that I used NAVIGATION_MODE_LIST instead of tabs. I run into similar issues when I called a fragment from another fragment e.g. click on a list item opening up the item details.
Now I call all fragments from the main activity which allows me to control the set up of the actionbar. Whenever the navigation list should disappear I just call NAVIGATION_MODE_STANDARD when the fragment is called and NAVIGATION_MODE_LIST for the other fragments.

Categories

Resources