I am trying to implement a ShareActionProvider
using the support library in a contextual action bar in my fragment. I face no issues implementing it in a normal action bar( onCreateOptionsMenu() ), but when i try it in the CAB ( onCreateActionMode() in MultiModeListener
interface), I get the error :
getActionProvider: item does not implement SupportMenuItem; returning null
Looking at the Android source at https://cells-source.cs.columbia.edu/plugins/gitiles/platform/frameworks/support/+/30837f1095c803f332f4a1c3f0917c8afdd50156/v4/java/android/support/v4/view/MenuItemCompat.java, the problem seems to be because my MenuItem
is not an instance of SupportMenuItem
:
public static ActionProvider getActionProvider(MenuItem item) {
if (item instanceof SupportMenuItem) {
return ((SupportMenuItem) item).getSupportActionProvider();
}
// TODO Wrap the framework ActionProvider and return it
Log.w(TAG, "getActionProvider: item does not implement SupportMenuItem; returning null");
return null;
}
Any ideas on how i can go about resolving this ?
Manifest :
<activity
android:name=".myactivity_ActionBarActivity"
android:theme="@style/Theme.AppCompat.Light"
android:windowSoftInputMode="stateUnchanged">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Activity :
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
public class myactivity_ActionBarActivity extends ActionBarActivity{
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.actionbaractivity_layout); //loads a fragment
}
}
fragment :
import android.support.v7.widget.ShareActionProvider;
import android.support.v4.view.MenuItemCompat;
import android.view.MenuItem;
import android.view.Menu;
import android.support.v4.app.Fragment;
...
...
@Override
public void onActivityCreated(Bundle savedInstanceState) {
...
...
//Handle Action mode events
myListView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
private ShareActionProvider mShareActonProvider;
....
....
@Override
public boolean onCreateActionMode(ActionMode mode,
Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.chatsession_contextmenu, menu);
//get the ShareActionProvider from the menu item
MenuItem item = menu.findItem(R.id.share_menu);
mShareActonProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
return true;
}
}
...
...
}
Menu layout file :
<?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/delete_menu"
android:title="Delete message"
myapp:showAsAction="ifRoom|withText"
android:icon="@drawable/ic_action_discard">
</item>
<item
android:id="@+id/share_menu"
android:title="Share message"
myapp:showAsAction="ifRoom|withText"
android:icon="@drawable/ic_action_share"
myapp:actionProviderClass="android.support.v7.widget.ShareActionProvider">
</item>
</menu>
Edit 1 :
The root of the problem seems to be the difference in the Menu
object that is being passed as argument to onCreateActionMode(ActionMode mode, Menu menu)
and onCreateOptionsMenu(Menu menu, MenuInflater inflater)
. Only the one in onCreateOptionsMenu
has the MenuWrapperICS
. Here is a screenshot of both objects in debug mode :
onCreateActionMode(ActionMode mode, Menu menu) :
onCreateOptionsMenu(Menu menu, MenuInflater inflater) :
Be careful to use the right MenuInflater when populating the IMenu in onCreateActionMode. When I use the one from the mode object, as you do in your fragment class, it doesn't create the support version of ShareActionProvider. I switched to using the MenuInflater from the parent AppCompatActivity class and it worked fine.
Given that the mode object is from the support library, one would assume it would use the support inflater, but apparently not.
I had an almost identical setup. The problem in my case was that Proguard was optimizing away the constructor of the
ShareActionProvider
. There is a bug that they while they do keep the class and methods ofActionProvider
classes detected in your XML, they don't keep the constructors or the class name.If you have a "Cannot instantiate class" warning in your log, then this would apply to you, too.
Here is the Android bug report that helped me.
And the proguard config I added was:
Are you sure that your activity extends
ActionBarActivity
?The problem is that the
MultipleModeListener
interface extends theandroid.view.ActionMode.Callback
, as can be seen in the source code at http://androidxref.com/4.4.2_r2/xref/frameworks/base/core/java/android/widget/AbsListView.java#6301. If you are usingShareActionProvider
from the support library, you need theandroid.support.v7.view.ActionMode.Callback
instead.The solution is to create your own ActionMode.CallBack implementation instead of using the framework's
MultipleModeListener
. This way you make sure that the support libraries are being used wherever required.For example :
Import the v7 version of
ActionMode
andActionBarActivity
in your fragmentCreate an
onClickListener
for your list view and usestartSupportActionMode
to start your customActionMode.CallBack
implementationCreate your custom
ActionMode.Callback
implementation