Android - Ques on order in which Fragment Options Menu called - android

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.

Related

Order of `onOptionsItemSelected` calls

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.

android startActivityFromChild - use of API

I am trying to understand the startActivityFromChild API.
The description says:
This is called when a child activity of this one calls
its startActivity(android.content.Intent)
or startActivityForResult(android.content.Intent,int) method.
I understand that child activity means an activity invoked by current (parent). The comment suggests that this API is called child when calls startActivity(), then why is the explanation write the parent (child activity of this) ?
Can someone give an example on how to use this API ?
The parent/child relationship between activities mentioned here is not actually the one between an activity and those it launches via startActivity().
It refers to the parent of embedded activities, such as those inside a TabActivity (now deprecated), or an ActivityGroup in general -- although to be frank, I do not know of any other subclasses of ActivityGroup, so the "in general" may be unnecessary. :)
It's basically used to redirect some events to the parent. For example:
public boolean onCreateOptionsMenu(Menu menu) {
if (mParent != null) {
return mParent.onCreateOptionsMenu(menu);
}
return true;
}
This implementation wouldn't make sense if the parent was the caller activity. However, in the case of tabs, you do want the parent activity to show the menu of its current (shown) tab.
There are quite a few doXfromChild() methods, and they're all related to this scenario (a child asking its parent activity to do something).
In short, the functionality related to these APIs is mostly deprecated since Fragments came out.

Menu onClick attribute and method argument

I'm practising adding menu items and trying to react to menu item clicks. According to the developer's guide, it says:
Tip: Android 3.0 adds the ability for you to define the on-click behavior for a menu item in XML, using the android:onClick attribute. The value for the attribute must be the name of a method defined by the activity using the menu. The method must be public and accept a single MenuItem parameter—when the system calls this method, it passes the menu item selected. For more information and an example, see the Menu Resource document.
However, the sample code in the same page doesn't follow the rule: the methods do not pass the MenuItem parameter. The sample code is:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.new_game:
newGame();
return true;
case R.id.help:
showHelp();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
My question is: Shouldn't method calls be newGame(MenuItem item) and showHelp(MenuItem item), instead of newGame() and showHelp()? When I tested my own, (MenuItem item) argument was needed in fact, otherwise, the app was crashing, even though it compiles correctly.
Any help would be appreciated.
onOptionsItemSelected is the alternative to defining onClick attributes and what is available prior to Android 3.0 (important if you want to be backward compatible). It is simply a different way of providing the same process flow. Of course, onClick has the potential to crash your application on runtime, rather than onOptionsItemSelected not handling a menu item (simply causing it to do nothing).

handle click on iconmenu item

I see that it's possible to handle a tap on a icon menù item or by implementing
onOptionsItemSelected
inside the acivity, or by using
onMenuItemClickListener
like onclick listener on a button. When is better to use the fist one method, and when the second one?
Because for my opinion, using an external listener makes more modular the code, but create a new class, but using the first way don't create new class, but makes code less modular...
There are use cases other than the ones outlined below, but I'm putting in the general cases that come up regularly.
onOptionsItemSelected
If you're using Fragments, you may want to use onOptionsItemSelected and consider adding menu items to the Action Bar the way that is described in Adding items to the Action Bar.
What this describes is implementing onCreateOptionsMenu inside your Fragment. To make this happen, you must call setHasOptionsMenu in onCreate.
protected void onCreate(Bundle savedInstanceState) {
this.setHasOptionsMenu(true);
}
Setting this will actually make the Activity call onCreateOptionsMenu which allows you to add the menu items.
#Override
public boolean onCreateOptionsMenu(Menu menu){
super.onCreateOptionsMenu(menu);
// add items corresponding to this Fragment
menu.add(...);
return true;
}
The reason I recommend this is that it allows you to put more of the menu handling code into your Fragment instead of the Activity to figure out which Fragment to call, etc.
In this case, clicking the menu item will call onOptionsItemSelected inside of your Fragment which I suggest.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.my_id1:
dothing1();
return true;
case R.id.my_id2:
dotghing2();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
More of a long winded answer, but this is the way to handle menu clicks inside your Fragment.
onMenuItemClickListener
In the case of onMenuItemClickListener, this is used when you DON'T want to use the pre-ready method above and implement your own.
What I mean by that is you implement OnMenuItemClickListener and generate the methods in the interface. You then assign the menu to call the Activity that implemented this where as the above option assumes what Activity to use based on the pre-ready implementation of the Activity to Fragment relationship.
If you are targeting API 14 or greater (ICS or above) you could implement an ActionProvider. If that's not an option then you could implement a base activity that will always populate the menu and handle any menu clicks using onOptionsItemSelected. This is a good approach to implement "About" or "Settings" menu items through all your activities.

savedInstanceState is always null

This is my savedInstaceState code:
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
savedInstanceState.putStringArrayList("todo_arraylist", Altodo);
Log.v("bundle", "Saved");
super.onSaveInstanceState(savedInstanceState);
}
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
{
Altodo = savedInstanceState.getStringArrayList("todo_arraylist");
Log.v("bundle", "Restored");
}
else
{
Log.v("bundle", "null");
}
setContentView(R.layout.main);
}
The logs always show the "bundle save" tag.
But in onCreate method, SavedInstanceState is always null.
I observed the exact same symptoms (reported as issue 133394) in a project with two Activities A and B that extend ActionBarActivity. Activity A is the main activity, and I always receive null for savedInstanceState in onCreate of its list fragment when returning from a detail view activity B. After many hours, this problem exposed itself to me as a navigation issue in disguise.
The following may be relevant to my setup and come from other answers on this page:
Given this answer, I made sure that fragment and activity each have unique IDs set.
There is no override of onSaveInstanceState without super call.
Activity A is specified as acitivy B's parent in AndroidManifest.xml, using both the android:parentActivityName attribute and the corresponding meta-data tag for earlier versions of Android (see "Providing Up Navigation").
Already without any corresponding creation code such as getActionBar() .setHomeButtonEnabled(true), activity B has a functioning back button (<) in its action bar. When this button is tapped, activity A reappears but with (a) all previous instance state lost, (b) onCreate always called, and (c) savedInstanceState always null.
Interestingly, when I tap the back button provided at the bottom edge of the emulator display (an open triangle that points to the left), activity A reappears just as it was left (i.e. its instance state fully retained) without invoking onCreate. So maybe something is wrong with navigation?
After more reading, I implemented my own navigation instructions to run in response to a tap on the back-button in activity B:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home)
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
Nothing related to restoring instance state of activity A changed. NavUtils also provide a method getParentActivityIntent(Activity) and navigateUpTo(Activity, Intent) that allow us to modify the navigation intent to explicitly instruct that activity A is not started fresh (and thus without saved instance state provided) by setting the FLAG_ACTIVITY_CLEAR_TOP flag:
If set, and the activity being launched is already running in the
current task, then instead of launching a new instance of that
activity, all of the other activities on top of it will be closed and
this Intent will be delivered to the (now on top) old activity as a
new Intent.
In my hands, this solves problem of lost instance state and could look like:
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()== android.R.id.home) {
Intent intent = NavUtils.getParentActivityIntent(this);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
NavUtils.navigateUpTo(this, intent);
return true;
}
return super.onOptionsItemSelected(item);
}
Note that this may not be the complete solution in other cases where a user can switch directly to activity B from within a different task (see here). Also, a possibly identical solution in behavior that does not make use of NavUtils is to simply call finish():
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()== android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
Both solutions work in my hands. I am only speculating that the original issue is a slightly incorrect default implementation of the back-button, and it may be related to that implementation invoking some kind of navigateUp that misses FLAG_ACTIVITY_CLEAR_TOP.
Did you check if you have an Id set for that view ( if a view it is/has...). onSaveInstanceState() is not called otherwise.
Check this link.
The state saved in this manner is not persisted. If the whole application is killed as you are doing during debugging, the bundle will always be null in onCreate.
This IMO is yet another example of awful Android documentation. It's also why most apps in the marketplace don't implement saving state properly (at all).
in Manifest add this line for activities
android:launchMode="singleTop"
for example:
<activity
android:name=".ActivityUniversity"
android:label="#string/university"
android:launchMode="singleTop"
android:parentActivityName="com.alkhorazmiy.dtm.ActivityChart">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.alkhorazmiy.dtm.ActivityChart" />
</activity>
How do you test it?
Imo the best way to test it is using the "Don't keep activities"-flag in Settings > Developer Options. If you don't have Developer Options in Settings, see Enabling On-device Developer Options.
Open your activity
Long-press home
Go to another application
Long-press home
Go back to your application
Shouldn't super.onSaveInstanceState(savedInstanceState); be the first line in your override?
Edit: War_Hero points out in the comments that the documentation on that topic indicates that no, it shouldn't be the first line.
Check your activity in AndroidManifest.xml and remove android:noHistory property if is true.
<activity
// ....
android:noHistory="false" />
To debug, consider implementing onRestoreInstanceState and placing a call to Log.d in this method. Then, in the emulator, hit ctrl-F11 or whatever to rotate the phone. Your call to Log.d should be hit.
Implement a method of onRestoreInstanceState
and put below code there
Altodo = savedInstanceState.getStringArrayList("todo_arraylist");
I found that when I override onSaveInstanceState() and actually save some data in the Bundle, instance state is restored. Otherwise it's not.
Ive managed same way arround. Instead of handling savedInstanceState Bundle on the onCreateView method, ive handled it on onCreate method and setting the passed value to a globar variable then acessing this variable on the onCreateView method.
Hope it helps.
https://developer.android.com/guide/topics/manifest/activity-element#lmode
From this you can see 'Similarly, if you navigate up to an activity on the current stack, the behavior is determined by the parent activity's launch mode.' Maybe you are in the 'standard' mode.
I was able to solve it with:
#Override public boolean onSupportNavigateUp()
{
onBackPressed();
return true;
}
still had parent set in the manifest. So when you press the up navigation button, now it acts like the back button.

Categories

Resources