Reputation: 161
I want to change the menu item's icon dynamically as I get notification from a server. However, I'm getting a NullPointerException
when the codes to change the menu item's icon run.
Codes I used to change the menu item's icon are defined in the onCreatOptionsMenu
method as follow:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// getMenuInflater().inflate(R.menu.main, menu);
this.menu = menu;
if (mDrawerLayout != null && isDrawerOpen())
showGlobalContextActionBar();
MenuInflater menuInflater = this.getMenuInflater();
menuInflater.inflate(R.menu.notification, menu);
return super.onCreateOptionsMenu(menu);
}
}
and in the updateCount
method, I am changing the icon as follow:
public void updateCount(int count) {
hot_count = count;
System.out.println("Value of count: " + count);
runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
if (hot_count > 0) {
if(hot_count>0)
{
if (menu != null) {
MenuItem item = menu.findItem(R.id.menu_hotlist);
if (item != null) {
item.setIcon(R.drawable.ic_notification1);
}
}
}
}
}
});
}
Here is my menuitem "notification" file:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>
<item android:id="@+id/menu_hotlist"
android:actionLayout="@layout/action_bar_notification_icon"
android:showAsAction="always"
android:icon="@drawable/ic_notification"
android:title="Notification" />
</menu>
Here's my logcat:
01-20 15:03:29.811: E/AndroidRuntime(10318): java.lang.NullPointerException
01-20 15:03:29.811: E/AndroidRuntime(10318): at com.xsinfosol.helpdesk_customer.TAB_Activity$3.run(TAB_Activity.java:294)
01-20 15:03:29.811: E/AndroidRuntime(10318): at android.os.Handler.handleCallback(Handler.java:730)
01-20 15:03:29.811: E/AndroidRuntime(10318): at android.os.Handler.dispatchMessage(Handler.java:92)
01-20 15:03:29.811: E/AndroidRuntime(10318): at android.os.Looper.loop(Looper.java:137)
01-20 15:03:29.811: E/AndroidRuntime(10318): at android.os.HandlerThread.run(HandlerThread.java:61)
01-20 15:04:04.881: I/System.out(11629)
Please help.
Upvotes: 14
Views: 21522
Reputation: 101
As the docs state here, you should use onPrepareOptionsMenu()
for any menu changes during the runtime of the Activity. It gets invoked whenever you call invalidateOptionsMenu()
.
Summary:
onCreateOptionsMenu()
onPrepareOptionsMenu()
invalidateOptionsMenu()
when you have detected a change and want to update the options menuUpvotes: 0
Reputation: 897
There are 3 steps:
MenuItem
variable .onCreateOptionsMenu
method assign your value (the target
menu) to it.change the icon when required.
public class NotificationActivity extends BaseActivity {
//#1
Menu globalMenuItem;
//other variables
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.notification_menu, menu);
//#2
globalMenuItem= menu.add(Menu.NONE,menuId, Menu.NONE, title);
globalMenuItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS)
.setIcon(R.drawable.notification_icon_1);
//other menu items
}
//#3 call this when required
private void changeIcon(){
globalMenuItem.setIcon(R.drawable.notification_icon_2);
}
//...
}
Upvotes: 0
Reputation: 1002
I've also had the same problem and @Dario answers works like a charm as long as you don't call invalidateOptionsMenu()
To solve this, I assign the drawable resource to a variable and call invalidateOptionsMenu()
where I want to change the icon and I set the icon in onCreateOptionsMenu()
. The code should be like this:
private int drawableResourceId = R.drawable.default_menu_icon;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.test_menu, menu);
menu.findItem(R.id.change_menu_item_icon).setIcon(drawableResourceId);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.change_menu_item_icon:
drawableResourceId = R.drawable.changed_menu_icon;
invalidateOptionsMenu();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
Upvotes: 6
Reputation: 1
I've had the same problem. Please make sure you have the following in your menu item (an icon and showAsAction set to always) :
android:icon="@android:drawable/ic_menu_delete"
app:showAsAction="always"
Upvotes: 0
Reputation: 2073
Looks like menu.getItem(index)
is returning null because menu was not inflated ( you have check mDrawerLayout != null && isDrawerOpen()
) or you might have index
that doesn't exists. Instead of relying on menu item index you can use resource id, also do check for null:
if (menu != null) {
MenuItem item = menu.findItem(R.id.your_menu_action);
if (item != null) {
item.setIcon(R.drawable.ic_notification1);
}
}
Update: based on you code i did example below that works. You can use it as base or for comparing to find why your code is not working. I don't know how @layout/action_bar_notification_icon
looks like so in your case might be problem there.
In this example ic_menu_delet
e is replaced by ic_menu_edit
once you click on menu item.
test_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/test_menu_item"
android:icon="@android:drawable/ic_menu_delete"
android:showAsAction="always"
android:title="Item1"/>
</menu>
Code:
private Menu menu;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
this.menu = menu;
getMenuInflater().inflate(R.menu.test_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.test_menu_item:
changeIcon();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
changeIcon() simulates your updateCount()
public void changeIcon(){
runOnUiThread(new Runnable() {
@Override
public void run() {
if (menu != null) {
MenuItem item = menu.findItem(R.id.test_menu_item);
if (item != null) {
item.setIcon(android.R.drawable.ic_menu_edit);
}
}
}
});
}
Upvotes: 10