I have given toolbar for each fragment in my app.
Following is code in the fragment to set toolbar. setToolbar is a method in Activity which is called from fragment using the interface.
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Toolbar toolbar = view.findViewById(R.id.toolbar);
if (mListener != null) {
mListener.setToolbar(toolbar);
}
}
Now since I am not removing toolbar when the fragment is destroyed it is causing a memory leak. I want to know where should I remove the toolbar fragment and how.
Any idea where and how should I release toolbar which is in the fragment?
As per my previously asked question Can I have toolbar for each fragment separately. How to handle navigation drawer I was told I can have a toolbar in each fragment but now I am facing memory leak.
Instead of creating toolbar for each fragment separately, create a single toolbar in the parent activity of those fragments.
If you are concerned about menu options in each fragment, then no need to worry. Just write setHasOptionsMenu(true) inside onCreateView method of each fragment. Also override onCreateOptionsMenu and onOptionsItemSelected in each fragment.
Activity toolbar will reflect the changes in menu options automatically.
NOTE: Always generate an activity from the template provided by Android Studio. It will save you both time and energy. You can always remove all the boiler plate code which you deem to be unnecessary.
The solution is to not set the toolbar for the activity. But if you want to, you can remove it in the Fragment.onStop().
If your toolbars look the same (component-wise), Have the Toolbar in your activity, and upon onAttach() of each fragment, pass the arguments like toolbar title, hasBack and ... to your activity and let the activity handle showing it.
This way you would never have a memory leak and also, everytime a fragment gets attached, the toolbar gets updated accordingly.
I suggest creating an interface like ToolbarInteractor and have two methods, setToolbar(title:String,hasBack:Boolean,...) and resetToolbar() and let your activity implement it. Then in your fragment, call ((ToolbarInteractor) getActivity()).setToolbar(...). Same goes for reset().
Yes, as above answer you can have one parent activity in which you can have toolbar implementation and the fragments are implemented in the same.
Now to customize your toolbar header you can implement a method interface and can use accordingly.
For brief & other option you may use this LINK
Related
I am a bit confused on how the Navigation component fits in the app behavior. It all looks nice and shiny in tutorials where you don't do things too complex but when implementing in real app, things seem different.
Before Navigation
Before implementing navigation I had to manually run fragment transactions. In order to do this, my fragment would implement an interface onFragmentAction which passed a bundle to the main Activity and in the activity based on the actions, replace the current fragment with another one.
The second part that needs handling is the top toolbar and the BottomAppBar. For instance BottomAppBar needs to have the FAB aligned differently on some fragments or hidden in others. Also the top ToolBar needs to be expanded on some or collapsed on others. To do this, I listened to FragmentManager.OnBackStackChangedListener and based on the fragment tag getSupportFragmentManager().getBackStackEntryAt(size - 1).getName() change the layout accordingly.
With Navigation
The first part seems to be easy to do: pass params and start new fragments. But I have no idea if navigation can handle the toolbars management or I need to keep managing it from my Activity.
Even though Alex's solution works, I would not recommend it for the purpose of managing the toolbar.
The toolbar should be part of your fragment's layout and each fragment should manage its own toolbar. you can inflate different menus for each fragment. even in the case of wanting to have the toolbar in the activity, I would recommend getting a reference to the toolbar form activity (through an interface) and then adding and manipulating its items in the fragment itself.
This would decouple your activity and fragment (which is one of the goals of having navigation graph and a router). a good rule of thumb is that imagine you want to remove the fragment, then you should not need to make any change to the activity.
The toolbar title is set based on 'label' value inside navigation graph, if you want to do something different with toolbar or BottomAppBar you can add addOnNavigatedListener inside your activity, and based on current destination do something.
findNavController(nav_host_fragment).addOnNavigatedListener { controller,
destination ->
when(destination.id) {
R.id.destination1 -> {
//Do something with your toolbar or BottomAppBar
}
R.id.destination2 -> {
//Do something with your toolbar or BottomAppBar
}
}
}
In your fragment:
NavController navHostFragment = NavHostFragment.findNavController(this);
NavigationUI.setupWithNavController(toolbar, navHostFragment);
When I click item on list item (Explore Fragment) it will negation to DetailFragment and when I click the back button on the toolbar it will return MainFragment.
if you want to reach to another fragment by calling on menu item, you must give to item id the the same id which is in the destination id.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return
item.onNavDestinationSelected(findNavController(R.id.nav_host_fragment))
|| super.onOptionsItemSelected(item)
}
<item android:id="#+id/dailyInfoFragment"
android:title="#string/action_settings"
android:orderInCategory="100"
app:showAsAction="never"/>
<fragment
android:id="#+id/dailyInfoFragment"
android:name="com.example.sonyadmin.infoPerDay.DailyInfoFragment"
android:label="fragment_daily_info"
tools:layout="#layout/fragment_daily_info"
/>
while having two Toolbars one for activity and another for Fragment
if I set setSupportActionBar for the Fragment toolbar it means I am loosing SupportActionBar for Activity toolbar Documentation. But is it possible to setSupportActionBar for fragment and Activity both toolbars parallel without affecting each other operating in their own scope . Thanks
No you can't do that, only a Activity has access to setSupportActionBar.
If you want to set it from your fragment use ((Activity)context).setSupportActionBar();
Is your goal just changing the Title and onClick on the menu items for a Toolbar?
Edit:
Try making a toolbar object and calling
toolbar.setMenu();
and then to listen to button clicks use
toolbar.setOnMenuItemClickListener();
I have an activity with a NavigationDrawer and a full screen fragment. Clicking on various items in the NavigationDrawer inflates a different fragment in the activity.
I would like to also swap in a different toolbar when launching a different fragment. The reason I want to do that instead of inflating a new menu is that the toolbar I want to swap in is a bit complicated and has things like an EditText in it.
Is there some way to do this either in the activity before inflating a fragment or maybe in the fragment?
Just include your Fragment specific toolbar in your Fragment's layout so that it's visible in your Fragment permanently.
Now in the onStart() method of your Fragment -
getActivity().getSupportActionBar().hide();
This will hide the activity's default toolbar so that it does not overlap with the Fragment's toolbar.
Then again in the onStop() method of your Fragment -
getActivity().getSupportActionBar().show();
So that the Activity's toolbar is visible again outside that Fragment.
each time you call a fragment use "invalidateOptionsMenu" and using fragment id you can set visibility of menuitems in toolbar... if that is what u need... hope it helps
I am using Android-ObservableScrollView library. Everything works great, but I have activity for holding fragments, so all views are encapsulated in the fragment. In activity there is only FrameLayout for holding fragments.
So I need to use Toolbar in my application, I have several ideas how to implement this.
Use Toolbar in activity, in this case my layout will have FrameLayout and Toolbar. In this way I have communicate with activity whenever I need to do something with toolbar, I can also obtain it by using getSupportedActionBar() from fragment.
Use Toolbar inside fragment (in its layout) setting in each fragment view creation. And each time I change fragment I have to add new Toolbar to the activity. In some fragment I am going to have different toolbars but not in all. Is it good approach to store Toolbar inside fragment.
The problem that I can see in using second approach, if there will be more than one fragment on the screen there will be also several toolbars.
Please suggest what will be the right way in this case.
Thank you.
You should use first method.
While using first method will have less problem then second one because in second method you have to define toolbar for many times which is not good programming.
I have a 3 page Fragment in my app, but I need each fragment to have a different ActionBar. For one fragment I have set the current code in the OnCreateView method that adds in an EditText to the ActionBar:
//mainActivityContext is the context for the Main Activity (This is a fragment file)
ActionBar actionBar = mainActivityContext.getActionBar();
// add the custom view to the action bar
actionBar.setCustomView(R.layout.actionbar_view);
search = (EditText) actionBar.getCustomView().findViewById(R.id.searchfield);
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM
| ActionBar.DISPLAY_SHOW_HOME);
Yet this EditText stays persistent throughout all of the ActionBar menus. I only want it on one. I have tried everything, menu.clear();, setHasOptionsMenu(true);, inflater.inflate(R.menu.different_file, menu);, but nothing has worked.
Any help?
There is a very good approach to go about this situation:
on each fragment's onActivityCreated() method call setHasOptionsMenu(true);
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
now you can override onCreateOptionsMenu() and onOptionsItemSelected() inside each fragment.
And also dont forget to call getActivity().supportInvalidateOptionsMenu(); inside onResume() of fragment.
I think this sample by google will be very helpful.
Since the actions are populated by the activity's options menu you can use Activity#invalidateOptionsMenu(). This will dump the current menu and call your activity's onCreateOptionsMenu/onPrepareOptionsMenu methods again to rebuild it.
If you're using action bar tabs to change your fragment configuration there's a better way. Have each fragment manage its own portion of the menu. These fragments should call setHasOptionsMenu(true). When fragments that have options menu items are added or removed the system will automatically invalidate the options menu and call to each fragment's onCreateOptionsMenu/onPrepareOptionsMenu methods in addition to the activity's. This way each fragment can manage its own items and you don't need to worry about performing menu switching by hand.