I'm inflating the menu and trying to find the view of one of the menu items in the following way:
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
// will print `null`
Log.i("TAG", String.valueOf(findViewById(R.id.action_hello)));
return true;
}
In the result null
is printed in Logcat. However if I add some delay before calling findViewById
, it returns correct View
object:
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(final Void... voids) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(final Void aVoid) {
// will print correctly android.support.v7.view.menu.ActionMenuItemView...
Log.i("TAG", String.valueOf(findViewById(R.id.action_hello)));
}
}.execute();
return true;
}
Of course this solution is very dirty and the minimal delay is unknown. Is there a way to register some callback for the menu inflated event. In other words: how can I call findViewById
with the menu item id to be sure that the view is already there and this call won't return null
?
. findViewById(R. id. retry) would always return null.
FindViewById<T>(Int32) Finds a view that was identified by the id attribute from the XML layout resource.
findViewById is the method that finds the View by the ID it is given. So findViewById(R. id. myName) finds the View with name 'myName'.
findViewById returns an instance of View , which is then cast to the target class. All good so far. To setup the view, findViewById constructs an AttributeSet from the parameters in the associated XML declaration which it passes to the constructor of View . We then cast the View instance to Button .
Just override public void onPrepareOptionsMenu(Menu menu)
.
Documentation says:
This is called right before the menu is shown, every time it is shown. You can use this method to efficiently enable/disable items or otherwise dynamically modify the contents.
The view for Menu
is created after calling onCreateOptionsMenu(Menu)
, that's why you can't access it subviews.
There are two ways to find the menu item view.
Frist way:-
Add a actionViewClass in your menu item, so that you can get view returned by getActionView. As getActionView() only works if there's a actionView defined for menuItem.
Add this in your menu item xml:-
<item
android:id="@+id/menuAdd"
android:icon="@android:drawable/ic_menu_add"
android:title="Add"
app:showAsAction="always"
app:actionViewClass="android.widget.ImageButton" />
In onCreateOptionsMenu method:-
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_item,menu);
View menuView=menu.findItem(R.id.menuAdd).getActionView();
Log.e("TAG", "onCreate: "+menuView );
return true;
}
Second way:-
The second way is to use a handler. Using this method you won't need to specify the time for the delay. Check the answer given by @davehenry here
You must call the super method when your code is finished or things just don't work as expected.
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
super.onCreationOptionsMenu(menu);
// calling the super completes the method now you code.
Log.i("TAG", String.valueOf(findViewById(R.id.action_hello)));
return true;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With