onOptionsItemSelected is called for wrong fragment (different fragment from backstack) - android

I have an issue with onOptionsItemSelected event.
My application consist of Activity, main fragment, multiple function fragments.
Activity's FragmentManager contains only one Fragment (MainFragment).
MainFragment's ChildFragmentManager contains up to 5 fragments.
All fragments are added by method:
public void addFragment(Fragment fragment) {
FragmentManager fm = getChildFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.frame, fragment);
ft.addToBackStack(fragment.getClass().getSimpleName());
ft.commit();
}
All child fragments have their own menus. Every fragment has the same superclass with
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
setHasOptionsMenu(true);
...
}
And it's own
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.some_menu, menu);
...
}
and
#Override
public boolean onOptionsItemSelected(MenuItem item) {
...
}
All Menus are inflated properly, but onOptionsItemSelected(MenuItem item) is always called for the first fragment in backstack:
Let's say that I have:
MainFragment (getChildFragmentManager)
DetailsFragment
EditFragment
SelectionFragment
Menu is inflated from SelectionFragment, but when I press menu button, it calls DetailsFragment.onOptionsItemSelected...
MainActivity does not have Menu (none of mentioned methods).
How can I solve this issue?
Regards
Jakub

Related

Fragment is not shown with activity start

I implemented a bottom Navigation that should be filled with three different Fragment classes.
My Problem is that if i start the activity the first Fragment layout is not shown, only if i go to tab2 and return to tab1.
I think it is a Problem with the LifeCycle but i have no idea how i can fix it.
my bottom Navigation class that handle the Navigation:
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = new RequestFragment();
break;
case R.id.navigation_dashboard:
fragment = new ResponseFragment();
break;
case R.id.navigation_notifications:
fragment = new LogfileFragment();
break;
}
final FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_container, fragment).commit();
return true;
And my Fragment class:
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_request, container, false);
you should add the first fragment when activity start. you just set first fragment on onNavigationItemSelected() method and it never called even you click on navigation View. you should add these lines in onCreate() method:
fragment = new RequestFragment();
final FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_container, fragment).commit();
You have to initialize the fragment inside onCreate() method.
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_activity);
...
fragment = new RequestFragment();
final FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_container, fragment).commit();
}
This will display the fragment in the container inside the view when your activity starts. Keep your onNavigationItemSelected method as it is.

When press back redrawing the actionbar menu

I added a refresh button to action-bar. When fragment loading that refresh button is creating in the action-bar. I have more than one fragment in my application, problem is when move between fragments and go back using back button using back button, action bar menu refresh button drawing several times. like this
following code I'm using
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_seebo_tv, container, false);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.seebo_tv, menu);
}
in main activity
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar actions click
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.action_refresh:
fragment=new ProgressFragment();
FragmentManager fragmentManagerProgress = getFragmentManager();
fragmentManagerProgress.beginTransaction().replace(R.id.container, fragment).addToBackStack(null).commit();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
how can I fix this?
Try moving the call to setHasOptionsMenu(true); from onCreateView to onCreate instead.
Here's an example of a fragment adding a menu item: https://stackoverflow.com/a/31935887/798464

Replacing Fragment does not change properly

The issue occurs when I attempt to switch from the Second Fragment to the First Fragment. I am using ActionBar Option Menu Icons to navigate back and forth between the different fragments.
Each fragment has its own menu that is associated with the individual option menu items. I cannot seem to figure out why I am able to transition from one the First Fragment to the Second Fragment, but am unable to do the reverse.
Does anything in my code stand out that would disable me from being able to navigate back to the previous fragment?
I was able to switch between the fragments without any issues in the past, but after I incorporated these option menu items to do the navigation, it stopped working.
Starting Fragment
public class SearchFragmentActivity extends Fragment implements OnClickListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.activity_search_fragment,
container, false);
btnBasketball = (ImageButton) view.findViewById(R.id.btnBasketball);
btnBasketball.setOnClickListener(this);
setHasOptionsMenu(true);
return view;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// TODO Add your menu entries here
menu.clear();
inflater.inflate(R.menu.navigation_search_event, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_more:
// do something with a dropdown
break;
}
return true;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btnBasketball:
changeFragment("Basketball");
break;
}
}
public void changeFragment(String sportName) {
Bundle bundle = new Bundle();
bundle.putString("SPORTNAME", sportName);
Fragment fragment = new SearchDetailsFragmentActivity();
fragment.setArguments(bundle);
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.setCustomAnimations(R.anim.cell_left_in,
R.anim.cell_right_out);
transaction.replace(R.id.searchFragment, fragment);
transaction.commit();
}
}
Second Fragment
public class SearchDetailsFragmentActivity extends Fragment {
TextView tvSportsName;
GridView gView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.activity_search_details_fragment,
container, false);
String sportsName = getArguments().getString("SPORTNAME");
tvSportsName = (TextView) view.findViewById(R.id.tvSportsName);
tvSportsName.setText(sportsName);
// SportAdapter sAdapter = new SportAdapter(getActivity(), lstSports);
gView = (GridView) view.findViewById(R.id.gridViewSearch);
setHasOptionsMenu(true);
return view;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// TODO Add your menu entries here
menu.clear();
inflater.inflate(R.menu.navigation_search_details_event, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_cancel:
changeFragment();
break;
}
return true;
}
public void changeFragment() {
Fragment fragment = new SearchFragmentActivity();
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.setCustomAnimations(R.anim.cell_left_in,
R.anim.cell_right_out);
transaction.replace(R.id.searchDetailsFragment, fragment);
transaction.commit();
}
}
Options Menu associated with Second Fragment
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" >
<item
android:id="#+id/action_cancel"
android:icon="#drawable/ic_content_remove"
android:orderInCategory="100"
android:title="#string/action_settings"
app:showAsAction="always"/>
</menu>
UPDATES
These changes allow me to navigate backwards from the SearchDetailsFragmentActivity >> SearchFragmentActivity using the SoftKey Back Button.
Changes to the changeFragment() method inside SearchDetailsFragmentActivity
public void changeFragment() {
Fragment fragment = new SearchFragmentActivity();
FragmentManager fm = getFragmentManager();
//FragmentTransaction transaction = fm.beginTransaction();
//transaction.setCustomAnimations(R.anim.cell_left_in,
//R.anim.cell_right_out);
//transaction.replace(R.id.searchDetailsFragment, fragment);
//transaction.commit();
fm.popBackStack();
}
inside the SearchFragmentActivity
public void changeFragment(String sportName) {
Bundle bundle = new Bundle();
bundle.putString("SPORTNAME", sportName);
Fragment fragment = new SearchDetailsFragmentActivity();
fragment.setArguments(bundle);
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.setCustomAnimations(R.anim.cell_left_in,
R.anim.cell_right_out);
transaction.replace(R.id.searchFragment, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
UPDATE 2
I placed a Log.e inside the OnOptionItemSelected() to see if the button was even firing properly and it appears as if it is not. There is nothing that is getting logged.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_cancel:
Log.e("IS THIS WORKING", "THIS IS WORKING"); <<< NOT FIRING
changeFragment();
break;
}
return true;
}
When replacing a fragment, you need to indicate whether or not that transaction is reversable (i.e. whether or not it goes onto the backstack). For the first fragment transaction, you usually won't want to do this (wouldn't want to pop to an empty view). For fragment replacements, you want to specify addToBackStack() with an optional tag (which can be later used with popBackStack(String)).
For example, in between these lines:
transaction.replace(R.id.searchDetailsFragment, fragment);
transaction.commit();
add:
transaction.replace(R.id.searchDetailsFragment, fragment);
transaction.addToBackStack(null);
transaction.commit();

Pressing back does not return to previous fragment

I have a problem with adding the fragment transactions to the back stack. I have a Main activity in which I populate my layout with a Menu Fragment:
public class MainActivity extends ActionBarActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getFragmentManager().beginTransaction().add(R.id.frag_container, new MainMenuFragment()).commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Then, inside the MainMenuFragment, the user chooses some option which results in replacing the menu fragment with some other fragment:
public class MainMenuFragment extends Fragment implements OnItemClickListener{
GridView grid;
FragmentManager manager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.main_menu_fragment, container, false);
manager = getActivity().getFragmentManager();
grid = (GridView) root.findViewById(R.id.gridView1);
grid.setAdapter(new MenuTileAdapter(getActivity()));
grid.setOnItemClickListener(this);
return root;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
FragmentTransaction trans = manager.beginTransaction();
if (position == 0){
trans.replace(R.id.frag_container, new BasicSettingsFragment());
trans.addToBackStack(null);
trans.commit();
}
}
}
For what i understand, this should make it so that when the user presses back button on their device, they will be brought back to the menu fragment, but instead this quits the app. What am i doing wrong?
In your Activity overwrite:
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
And probably you need to use in every commited fragment transaction:
FragmentTransaction.addToBackStack(null);
Your code is a mixup, you use ActionBarActivity from appcompat and not using getSupportFragmentManager() and the fragments import should be the appcompat one if you decide to use it. If not, use Activity instead of ActionBarActivity and the simple Fragment import with FragmentManager
Add this to your activity android:configChanges="keyboardHidden|orientation|screenSize"
This will stop your activity from restarting when you rotate.
use setRetainInstance(true) on fragments.
You are not adding the MainMenuFragment to the back stack. You can try this one on your activity:
getFragmentManager().beginTransaction().add(
R.id.frag_container, new MainMenuFragment()).
addToBackStack(null).commit();
When you add or replace a fragment with the FragmentManager, you need to manually add the old fragment to the backstack with addToBackStack() before calling commit().

Adding Menu Item dynamically from SherlockActionBar Fragment Tabs

So I've been working on and Android app that has a Navigation Bar on the top with several Tabs, and that part is working fine but now I want to be able to dynamically add Menu Items to the Action Bar from different Fragments (since some Fragments may have different options available). So far no matter what I've tried I can't seem to get the onCreateOptionsMenu to be called. Here's what I have so far
//First I have a holder class that is used to navigate between the different Fragment Tabs
public class ActionHolder extends SherlockFragmentActivity implements ActionBar.TabListener {....
//And then I have this method for switching Fragments based on what Tab is selected
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
int selectedTab = tab.getPosition();
if (selectedTab == 0) {
SalesMainScreen salesScreen = new SalesMainScreen();
ft.replace(R.id.content, salesScreen);
}
else if (selectedTab == 1) {
ClientMainScreen clientScreen = new ClientMainScreen();
ft.replace(R.id.content, clientScreen);
}.....
Now here is one of the Tab's Fragments (the SalesMainScreen) that I want to have a few menu items added to the Action Bar
#Override
public void onCreate (Bundle savedInstanceState) {
Log.i("message","the oncreate method was called");
setHasOptionsMenu(true);
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup group, Bundle saved) {
return inflater.inflate(R.layout.salesmainscreen, group, false);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Log.i("message", "the oncreatemenu method called");
inflater.inflate(R.menu.menu_refresh, menu);
super.onCreateOptionsMenu(menu, inflater);
}
I see the OnCreate Log message being called but I don't see the onCreateOptionsMenu Log being called at all. Also, I know that sometimes the imports cause issues, but when I import the Sherlock Menu and Menu Inflater I get all kinds of error messages on the OnCreateOptionMenu method about them not being compatible. Is it possible in this setup to dynamically add Menu Items to the Action Bar, or should I just add the items and then just don't do any actions on the ones that don't apply to the fragment that is being displayed?
I have an app using SherlockActionBar and tabs, with each tab containing a SherlockFragment. The main activity has its own menu in the action bar, and one of the fragments adds a search item to the action bar menu.
The main activity has the following:
class MainActivity extends SherlockFragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
ActionBar bar = getSupportActionBar();
bar.addTab(createThingOneTab());
bar.addTab(createThingTwoTab());
bar.addTab(createThingThreeTab());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getSupportMenuInflater().inflate(R.menu.activity_main, menu);
}
}
The fragment in the tab has the following:
class ThingOneFragment extends SherlockFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
MenuItem search = menu.add("Search");
search.setIcon(android.R.drawable.ic_menu_search);
search.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
...
}
}
When I start the main activity, the tab shows ThingOneFragment by default and I see the search icon in the action bar. When I select the other tabs, the search icon disappears. You do need to make sure that you are using the Sherlock classes for Menu, MenuInflater, etc.
I'm not sure if it makes a difference but my TabListener looks like this:
private TabListener createTabListener(final Class<? extends Fragment> clazz) {
return new TabListener() {
private Fragment mFragment;
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// no action
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(activity, clazz.getName());
}
getSupportFragmentManager().beginTransaction()
.replace(android.R.id.content, mFragment)
.commit();
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// no action
}
};
I'm not sure if that is causing your issue or if it's even the correct way of handling tabs but I include it for completeness.

Categories

Resources