【问题标题】:why MenuItemCompat.getActionProvider returns null?为什么 MenuItemCompat.getActionProvider 返回 null?
【发布时间】:2026-01-28 05:15:01
【问题描述】:

我尝试在我的应用程序的操作栏上使用 android.support.v7.widget.ShareActionProvider。所以我按照android文档中的示例进行操作,但遇到了一些问题。
这是我的菜单 xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myapp="http://schemas.android.com/apk/res-auto" >

    <item
        android:id="@+id/action_share"
        android:orderInCategory="100"
        android:icon="@drawable/ic_action_share"
        android:title="@string/action_share"
        myapp:showAsAction="ifRoom"
        myapp:actionProviderClass="android.support.v7.widget.ShareActionProvider" />

</menu>

这是我创建分享操作按钮的代码:

@Override
public void onCreateOptionsMenu (Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.share, menu);
    MenuItem shareItem = menu.findItem(R.id.action_share);
    ShareActionProvider mShareActionProvider = (ShareActionProvider)MenuItemCompat.getActionProvider(shareItem);
    mShareActionProvider.setShareIntent(getDefaultIntent());
    super.onCreateOptionsMenu(menu, inflater);
}

我的问题是:

  1. MenuItemCompat.getActionProvider(shareItem) 总是为我返回 null,这是为什么呢?
  2. 当我评论这些行时,分享按钮出现在栏上,但点击时什么也不做,如何解决(如果问题 1 无法解决)?

顺便说一句,我检查了 MenuItemCompat.getActionProvider 的代码,看起来这个方法将检查菜单项是否实现 SupportMenuItem 接口,如果不是则返回失败。我该如何处理?

【问题讨论】:

  • 我能够重复 MenuItemCompat 总是返回 null 的场景。我的问题是我使用命名空间 android: 而不是定义命名空间,例如 app: 或 myapp:。在这两种情况下,我都验证了 menu.findItem 正在返回一个 instanceof SupportMenuItem。
  • 我找到了我犯2个错误的原因,应用程序主题应该是theme.appcompat.*,我使用了标准的全息它们,并且似乎片段中onCreateOptionsMenu的执行在活动之前。
  • 我已经使用了 appcompat 主题,我无法理解您的第二个原因的相关性。这个问题对我来说仍然没有解决。见*.com/questions/24219842/…

标签: java android


【解决方案1】:

在我的情况下,menu.xml错误的命名空间

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
  <item android:id="@+id/menu_item_share"
        app:actionProviderClass="android.support.v7.widget.ShareActionProvider"/>

注意app:actionProviderClass="android.support.v7.widget.ShareActionProvider":应该有

  • 正确的android.widget android.support.v7.widget
  • 正确的命名空间android app)。

不幸的是,编译器编译它没有错误,只有 Android Studio 会发出带有下划线的通知。

【讨论】:

    【解决方案2】:

    如果有人想保持progaurd 并仍然使用代码:

    ShareActionProvider mShareActionProvider = (ShareActionProvider)MenuItemCompat.getActionProvider(shareItem);
    

    只需要添加到proguard:

    -keep class android.support.v7.widget.ShareActionProvider { *; }
    

    【讨论】:

    • 这是对我有用的解决方案。由于 Android 支持库现在被 AndroidX 取代,我不得不将其更改为 -keep class androidx.appcompat.widget.ShareActionProvider { *; }。但知道为什么会这样吗?既然类被显式实例化,为什么 proguard 会删除它?我不明白。
    【解决方案3】:

    这是使 ShareActionProvider 不为空的唯一解决方案...我使用 set ActionProvider 代替...请参阅下面的代码:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.messages_activity_menu, menu);
        MenuItem menuItem = menu.findItem(R.id.menu_item_share);
        shareActionProvider = new ShareActionProvider(this);
        MenuItemCompat.setActionProvider(menuItem, shareActionProvider);
    
        return super.onCreateOptionsMenu(menu);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    
        if(item.getItemId() == R.id.menu_item_share){
            onShareAction();
        }
    
        return super.onOptionsItemSelected(item);
    }
    
    private void onShareAction(){
        // Create the share Intent
        String playStoreLink = "https://play.google.com/store/apps/details?id=" + getPackageName();
        String yourShareText = getResources().getString(R.string.share_text) + playStoreLink;
        Intent shareIntent = ShareCompat.IntentBuilder.from(this).setType("text/plain").setText(yourShareText).getIntent();
        // Set the share Intent
        if (shareActionProvider != null) {
            shareActionProvider.setShareIntent(shareIntent);
        }
    }
    

    和...xml

     <?xml version="1.0" encoding="utf-8"?>
     <menu xmlns:android="http://schemas.android.com/apk/res/android" >
         <item
        android:id="@+id/menu_item_share"
        android:icon="@drawable/ic_action_share"
        android:showAsAction="ifRoom|withText"
        android:title="@string/menu_item_share" />
     </menu>
    

    以及其他可能需要检查的事项:

    活动必须扩展 ActionBarActivity:

    MyActivity extends ActionBarActivity
    

    检查并使用此导入:

    import android.support.v4.app.ShareCompat;
    import android.support.v4.view.MenuItemCompat;
    import android.support.v7.app.ActionBar;
    import android.support.v7.app.ActionBar.OnNavigationListener;
    import android.support.v7.app.ActionBarActivity;
    import android.support.v7.widget.ShareActionProvider;
    

    在 AndroidManifest.xml 中,将此行放入您的活动标签属性中:

    android:theme="@style/Theme.AppCompat.Light"
    

    如果您不知道如何导入 v7 和 v4 兼容库,请参阅:http://developer.android.com/tools/support-library/setup.html

    【讨论】:

    • "Here this is the only solution that works to make ShareActionProvider not null"。好吧,这不是真的。看我的回答。
    • 您可以在不扩展 ActionBarActivity 的情况下轻松完成,我将 Intent shareIntent = ShareCompat.IntentBuilder.from(this).setType("text/plain").setText(yourShareText).getIntent(); 更改为 Intent shareIntent = new Intent(Intent.ACTION_SEND).putExtra(Intent.EXTRA_TEXT, yourShareText).setType("text/plain");,它对我有用
    【解决方案4】:

    确保您的类扩展 AppCompatActivity 而不仅仅是 Activity。

    注意:已编辑以反映更新的应用兼容性库。

    【讨论】:

    • ActionBarActivity 现已弃用。
    • 同上,AppCompatActivity 是更好的选择
    【解决方案5】:

    经过一番阅读,其中可能包括你们中的一些回复,终于解决了这个问题:

    1. Share_Menu.xml。 确保您有一个自定义命名空间,并且 actionProvider 类来自该自定义命名空间以及正确的值:android.support.v7.widget.ShareActionProvider

      <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:myapp="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/action_share" android:title="@string/action_detail_share" myapp:showAsAction="always" myapp:actionProviderClass="android.support.v7.widget.ShareActionProvider"></item> </menu>

    2. Detail_Activity.java
      2.1。继承自 ActionBarActivity 而不是 Activity
      2.2.添加正确的导入

      import android.support.v4.app.Fragment; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.ShareActionProvider;

    3. AndroidManifest.xml 添加 android:theme="@style/Theme.AppCompat.Light"

      <activity android:name=".detail_activity" android:label="@string/title_activity_detail_activity" android:theme="@style/Theme.AppCompat.Light" android:parentActivityName=".main_activity" >

    4. Build.gradle
      4.1。就我而言,为了安全起见,我在调试中关闭 ProGuard

      debug { runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' }

    4.2。确保您在依赖项中有以下编译部分

    `compile 'com.android.support:appcompat-v7:20.0.+'` 
    

    【讨论】:

      【解决方案6】:

      我的应用程序中有相同的 nullPointer 问题。正如@josh527 所说,我忘记为我的应用程序定义一个自定义 xml 命名空间。我知道这不是你的问题,但有些人可能会像我一样看到你的帖子而没有看到,所以我只是想发现它;)

      【讨论】:

        【解决方案7】:

        我遇到了同样类型的错误。 MenuItemCompat.getActionProvider 返回 null。

        我的问题出在 ProGuard 中。关闭 ProGuard 为我解决了这个问题。

        【讨论】:

        • 无需完全关闭proguard,只保留搜索类-code.google.com/p/android/issues/detail?id=58508
        • 只需添加 -keep class android.support.v7.widget.ShareActionProvider { *; }-keep class android.support.v7.widget.SearchView { *; },一切都会正常
        【解决方案8】:

        尝试添加到活动单元

        import android.support.v4.view.MenuItemCompat;
        

        我遇到了同样的问题,已经解决了。

        【讨论】:

          【解决方案9】:

          变量: Android.Support.V7.Widget.ShareActionProvider shareActionProvider;

          this.MenuInflater.Inflate(Resource.Menu.share_action_provider, menu);
          var shareItem = menu.FindItem(Resource.Id.menu_item_share_action_provider_action_bar);
          MenuItemCompat.SetShowAsAction (shareItem,  MenuItemCompat.ShowAsActionIfRoom);
          var actionprov = new Android.Support.V7.Widget.ShareActionProvider (this);
          MenuItemCompat.SetActionProvider (shareItem, actionprov);
          var test =  MenuItemCompat.GetActionProvider (shareItem);
          shareActionProvider = test.JavaCast<Android.Support.V7.Widget.ShareActionProvider>();
          var intent = new Intent(Intent.ActionSend);
          intent.SetType("text/plain");
          intent.PutExtra(Intent.ExtraText, "ActionBarCompat is Awesome! Support Lib v7 #Xamarin");
          shareActionProvider.SetShareIntent (intent);
          return base.OnCreateOptionsMenu(menu); 
          

          这对我有用...我刚刚创建了自己的 shareactionprovider !我自己设置它,然后得到它......也许有一些代码甚至不需要......但它有很多转换并确保你一直使用正确的,如果你只是输入“ShareActionProvider”你是实际上使用V4 ..!而不是 V7

          【讨论】:

            【解决方案10】:

            您应该更改 onCreateOptionsMenu 函数的声明和定义。您已经更改了基类的函数声明。这意味着该方法未被覆盖。

            试试这个:

            @Override
            public boolean onCreateOptionsMenu (Menu menu) {
            
                inflater.inflate(R.menu.share, menu);// declare a local layout inflater
                MenuItem shareItem = menu.findItem(R.id.action_share);
                ShareActionProvider mShareActionProvider = (ShareActionProvider)MenuItemCompat.getActionProvider(shareItem);
                mShareActionProvider.setShareIntent(getDefaultIntent());
            //    super.onCreateOptionsMenu(menu, inflater);   <--- Remove this line or put in the first line because base class constructor should be called in the first line of the method.
            
            return super.onCreateOptionsMenu(menu);//<-- Add this line to set the menu after adding menu items
            }
            

            【讨论】:

              【解决方案11】:

              对于 Android Pie,动作提供程序类再次更改:

              app:actionProviderClass="androidx.appcompat.widget.ShareActionProvider"
              

              【讨论】:

                【解决方案12】:

                还有另一个潜在的相关问题。如果您的 MenuItem 始终出现在 ActionBar 中,请使用以下代码:

                menuItem?.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS) 
                

                生成的菜单项将不起作用(它将可见,但未启用)。有两种选择,要么改变 ShowAsAction 类型,要么直接在 onCreateOptionsMenu() 函数中调用 setShareIntent:

                this@MyAwesomeActivity.runOnUiThread(java.lang.Runnable {
                     actionProvider.setShareIntent(shareIntent)
                })
                

                【讨论】: