I put a couple of breakpoints in onCreate (one at the beginning, and one at the end of the method), and I also put one at the beginning of onCreateOptionsMenu. The onCreate method is called first, and before it finishes onCreateOptionsMenu is called.
I'm trying to separate the Fragment navigation code in my app, so I have a couple of objects that I delegate onCreateOptionsMenu to depending on if the app is running on phone/tablet (I'm using screen size to determine this, my layout file for large screens has a View I check for after the layout is inflated). The problem I'm having is, I create these objects in onCreate, and I'm getting a null pointer exception when I reference the object in onCreateOptionsMenu.
The onCreate method is called first, and before it finishes onCreateOptionsMenu is called.
That will be true on devices and apps with an official Honeycomb-style action bar. If there is no action bar, onCreateOptionsMenu() should not get called until the user calls up the menu, typically by pressing the MENU button.
(I'm using screen size to determine this, my layout file for large screens has a View I check for after the layout is inflated)
That test will break very shortly, once Ice Cream Sandwich ships. From what I can tell, ICS phones will have action bars (though perhaps not system bars).
In my case on Android 2.3 and with FragmentActivity from v4-support library the order of life-cycle methods invoke is following:
07-18 18:29:21.629 20183-20183/? I/onCreate:
07-18 18:29:21.719 20183-20183/? I/onStart:
07-18 18:29:21.719 20183-20183/? I/onResume:
07-18 18:29:21.739 20183-20183/? I/onCreateOptionsMenu:
I found if in onResume() I call
invalidateOptionsMenu();
then onCreateOptionsMenu(Menu menu) is called afterward - as per the activity life cycle (I think that's the correct term here), as indicated by #tir38
#Override
public void onResume() {
super.onResume();
invalidateOptionsMenu();
}
Addition in above answer,
In case of ICS and Honeycomb onCreateOptionsMenu is called after onCreate and onPostCreate while in Gingerbread and earlier versions it is called after onCreate but before onPostCreate. Thats the only difference I found.
In my experience ActionBarActivity from support v7 onCreateOptionsMenu() called in setContentView() method in the middle of onCreate() it is appear on 4.1.1.
But on 4.4 another story onCreateOptionMenu() called after onCreate(). Also I don't know it may be immediately after, maybe not. But is fact after. I didn't test on other versions but 4.1.1 is first where I had have a trouble with init order.
i suggest to create a callback-function in your fragment to avoid timing issues with onResume() and onCreateOptionsMenu().
doing the following works flawless for me:
create and add your fragment to your activity
leave a reference of this fragment in your activity
create a public method doSomethingWithTheMenu() in your fragment
call this method from within your activity when onCreateOptionsMenu(Menu menu) is called.
example:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (this.myFragment != null) {
this.myFragment.doSomethingWithTheMenu(menu);
}
return true;
}
Related
Why when I click on some button in AppBar, first is called onOptionsItemSelected from Activity and then (if I return false) the onOptionsItemSelected on Fragment is called?
I thought that if there is override for onOptionsItemSelected on Fragment, it gets called first and calls Activity onOptionsItemSelected only if I return false.
It is possible that someone changed the order in some configuration? I am working on quite large project and I am not sure if someone not altered default behavior.
I am currently learning Robolectric to test for Android and I am having trouble obtaining my application's menu.
Right now, Robolectric's getOptionsMenu() is returning null. The code itself works fine but the test always returns null for the options menu.
My code is the following
#Test
public void onCreateShouldInflateTheMenu() {
Intent intent = new Intent();
intent.setData(Uri.EMPTY);
DetailActivity dActivity = Robolectric.buildActivity(DetailActivity.class, intent).create().get();
Menu menu = Shadows.shadowOf(dActivity).getOptionsMenu(); // menu is null
MenuItem item = menu.findItem(R.id.action_settings); // I get a nullPointer exception here
assertEquals(menu.findItem(R.id.action_settings).getTitle().toString(), "Settings");
}
Does anyone know why Robolectric is returning null? Did I miss any dependencies?
The onCreateOptionsMenu will be called after oncreate so to make sure that you can see your menu try
Robolectric.buildActivity(DetailActivity.class, intent).create().resume().get();
or you can make sure the activity is visible
Robolectric.buildActivity(DetailActivity.class, intent).create().visible().get();
From docs
What’s This visible() Nonsense?
Turns out that in a real Android app, the view hierarchy of an
Activity is not attached to the Window until sometime after onCreate()
is called. Until this happens, the Activity’s views do not report as
visible. This means you can’t click on them (amongst other unexpected
behavior). The Activity’s hierarchy is attached to the Window on a
device or emulator after onPostResume() on the Activity. Rather than
make assumptions about when the visibility should be updated,
Robolectric puts the power in the developer’s hands when writing
tests.
So when do you call it? Whenever you’re interacting with the views
inside the Activity. Methods like Robolectric.clickOn() require that
the view is visible and properly attached in order to function. You
should call visible() after create().
Android: When is onCreateOptionsMenu called during Activity lifecycle?
I am adding a Up button to my Android application. The app's minimum SDK is 14, and I am testing it with an HTC phone on SDK version 15.
The activity is a subclass of android.app.Activity (not ActionBarActivity from the support package).
ActionBar style display options includes the homeAsUp flag, and I am able to see the standard arrow. However, clicking on the logo does nothing.
I have connected the debugger, and I am able to see that the onOptionsItemSelected method is not called at all. This cannot be because of misspelt name, because other menu items (e.g., Settings) do work (and I can see in the debugger that onOptionsItemSelected method gets called).
The parentActivityName and meta-data PARENT_ACTIVITY are set correctly (although I believe this would only matter if the method got called).
Is there anything I am missing? And how do I get the up button to work?
I encountered the same issue "onOptionsItemSelected" not called when using the ActionBarDrawerToggle it seems like the solution is setting this listener - it is called when the Up button is clicked.
drawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish(); // or any other code you want to run here
}
});
I was reading the help section on google's android page on OptionsMenus and ActionsBars:
http://developer.android.com/guide/topics/ui/actionbar.html
And they included a note that stated that when using fragments, the activity's onOptionsItemSelected method would be called beforethe fragment's is called, their by making it necessary to include the default: return super.onOptionsItemSelected at the end of the onOptionsItemSelected method definition. They included the following method example but did not state if this was meant to be an example within an Activity definition or a Fragment definition. I was a little confused on this and wanted to ask for clearification. based on the use of "super" it would suggest it's inside the fragment getting passed up to the Activity, but this disagrees with their statement that the Activity gets called first. If it's meant to be an example in the Activity and "super" refers to the parent Application class, then I am not clear on how it gets referred back to the Fragment. Any notes of clearification would be appreciated.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_search:
openSearch();
return true;
case R.id.action_compose:
composeMessage();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Your MyActivity extends Activity and thus inherits its methods, one of which is onOptionsItemSelected() that you are overriding.
Calling super.whatever() says: I want to override this method whatever()from the superclass Activity, but still run the method as defined there. Basically, you are adding something to that method. It's what you typically do onCreate, for example.
In this case, returning false would mean that, if ID is different from the mentioned twos, we're done - menu managing can stop here. Obviously we are not, as we want the fragment to receive its call.
So: your activity overrides the superclass method to manage the first two menu items, then calls the superclass method to keep things running and say hey, there might be something that has not be managed here.
I have various types of fragment in my application and there are 3 icons on ActionBar (filter, refresh and sort) but I don't want to show all 3 icons in each of the fragments. I have to show only some of them according to the fragment.
Similar thing I want to do with left drawer. On some fragments I want to show left drawer whereas don't want to display left drawer on others.
I have a Activity class in my application on which I am attaching these fragments and currently I am handling these two things in this class and code has become mess with if-else conditions.
So right now I am checking fragment name and then setting action bar icons and left drawer attributes according to it.
Please tell me a better way to do it( preferably to handle this in Fragment itself)
Thanks
Fragments have access to their activity through getActivity() function which will return non-null activity after onAttach() is called (and before onDetach()). Once the fragment has the activity it can tell it to do whatever you were doing right in the activity manually with checks, including changing the action bar buttons.
In order to show the options depending on the fragment, you can simply do the following:
Add setHasOptionsMenu(true) to the onCreate() method of the fragment and tell the Activity to redraw its options menu.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
getActivity().invalidateOptionsMenu();
}
Next override the onCreateOptionsMenu() method to inflate the options that you want for your fragment.
// No support library - support library api slightly different
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Add Fragment menu elements to Activity menu elements
inflater.inflate(R.menu.myfragmentmenu, menu);
super.onCreateOptionsMenu(menu,inflater);
}
Finally make sure to capture all option items in the onOptionsItemSelected() method of your activity.
(Important note: make sure to replace fragments instead of adding them. Otherwise onCreateOptionsMenu() will be called for each fragment.)
In order to disable and enable the drawer, you can add the following method to your Activity and call it from your fragment:
public void toggleDrawer(boolean enabled) {
if (enabled) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
mDrawerToggle.setDrawerIndicatorEnabled(true);
} else {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
mDrawerToggle.setDrawerIndicatorEnabled(false);
}
}
Create a new project from a sample project called ActionBarCombat and also download this sample application here http://www.learn2crack.com/2014/06/android-sliding-navigation-drawer-example.html
I once combined the two to come up with an application has action bar attributes as well as left drawer
To structure your code a bit why don't you create some methods in your activity like displayRefreshIcon(boolean visible) in which you handle the visibly of these items.
From your fragment you can call these methods (like frangulyan suggests) through the getActivity() function.
If (getActivity() != null && getActivity() instanceof MyActivity) {
((MyActivity)getActivity()).displayRefreshIcon(true);
}
In main thread or usual it is somehow impossible to do make changes in the activity itself, because fragments are separated module who are attached with activities but not the part of them.
But there is a shortcut that is to send message (handler) to activity to update the show the respective actionbar components
(most probably if you are using this fragment only for specific activity).
There you should make a base fragment and each fragment should extend baseFragment and at onResume method you have to check instance of Fragment then according to them you can update actionBar View.
Using any type of fragment, you should just have access to the methods (you have to override them): onCreateOptionsMenu, onPrepareOptionsMenu and onOptionsItemSelected. These methods should provide you with plenty of handles to create a menu per fragment. You could create a menu layout file per fragment and handle them in the method designed to do so. The methods:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.overviewmenu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}