如何动态更改ActionBar菜单项的图标

13

我希望根据从服务器接收到的通知动态更改菜单项的图标。但是,当执行更改菜单项图标的代码时,我遇到了一个NullPointerException

我在onCreateOptionsMenu方法中定义了更改菜单项图标的代码,如下所示:

 @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);
     }
 }

在`updateCount`方法中,我按照以下方式更改图标:
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);
                        }
                    }
                }
            }                   
        }
    });
}

这是我的“通知”菜单项文件:

<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>

以下是我的日志记录:

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)

请帮忙。

5个回答

10

看起来 menu.getItem(index) 返回 null 是因为菜单没有被实例化(你需要检查 mDrawerLayout != null && isDrawerOpen())或者 index 不存在。不要依赖于菜单项的索引,可以使用资源 ID, 同时也需要检查是否为 null:

if (menu != null) {
    MenuItem item = menu.findItem(R.id.your_menu_action);
    if (item != null) {
        item.setIcon(R.drawable.ic_notification1);
    }
}
更新:根据您的代码,我做了下面的示例,它可以正常工作。 您可以将其用作基础或进行比较,以查找为什么您的代码不起作用。 我不知道@layout/action_bar_notification_icon是什么样子,因此在您的情况下可能存在问题。
在此示例中,一旦单击菜单项,ic_menu_delete将被ic_menu_edit替换。 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>

代码:

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() 模拟了您的 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);
                }
            }
        }
    });
}

我实现了你的代码,但它没有改变图标。先生,请告诉我如何更改图标。 - ankur arora
菜单返回 null。 - ankur arora
menuInflater.inflate() 方法被调用了吗?并且你传递的资源是正确的吗? - Dario
请您详细说明一下吗? - ankur arora
@ankur-arora 也许你在某个地方调用了 invalidateOptionsMenu()。这可能会将图标恢复为其默认值。 - Zinc
显示剩余4条评论

6

我曾经遇到同样的问题,@Dario 的回答非常好用,只要不调用invalidateOptionsMenu()

为了解决这个问题,我将可绘制资源分配给变量,并在需要更改图标的位置调用invalidateOptionsMenu(),然后在onCreateOptionsMenu()中设置图标。代码应该像这样:

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);
}

1
太棒了,我的朋友!+1 - DarkCygnus
1
1+ 超级经典! - RonTLV

0

有三个步骤:

  1. 定义一个全局的MenuItem变量。
  2. onCreateOptionsMenu方法中将你的值(目标菜单)分配给它。
  3. 在需要时更改图标。

     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  在需要时调用此方法
       private void changeIcon(){
           globalMenuItem.setIcon(R.drawable.notification_icon_2);
       }
       //...
    }
    

0

我曾经遇到过同样的问题。请确保您的菜单项中包含以下内容(图标和showAsAction设置为always):

android:icon="@android:drawable/ic_menu_delete" 
app:showAsAction="always"

0
根据文档所述,您应该在Activity运行时使用onPrepareOptionsMenu()来进行任何菜单更改。每当您调用invalidateOptionsMenu()时,就会调用它。
总结:
  1. onCreateOptionsMenu()中初始化菜单
  2. 所有需要动态更新的内容都放在onPrepareOptionsMenu()
  3. 当检测到更改并希望更新选项菜单时,请调用invalidateOptionsMenu()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接