I'm working in my Android project developing with a HTC Desire (Gingerbread 2.3.7) and a Google Nexus 7 (Jelly Bean 4.3). I need to send some data from MainActivity to InfoActivity, so I use an intent. In this InfoActivity, I also have a menu item in the action bar to refresh the info.
In InfoActivity I show the data to the user. But this is not the problem, the problem is with the menu. Look at the following code:
public class ShowInfoActivity extends ActionBarActivity {
private MenuItem menuItem = null;
// ...
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
new OneTask().execute(...);
// ...
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
case R.id.refresh:
menuItem = item;
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private class OneTask extends AsyncTask<Object, Void, String> {
// ...
@Override
protected void onPreExecute() {
MenuItemCompat.setActionView(menuItem,
R.layout.actionbar_indeterminate_progress);
MenuItemCompat.expandActionView(menuItem);
}
// ...
@Override
protected void onPostExecute(String result) {
MenuItemCompat.collapseActionView(menuItem);
MenuItemCompat.setActionView(menuItem, null);
}
}
Obviously, the first time it's executed, menuItem=null, so it must crash. Incredibly, in HTC it works fine but in Nexus it obviously crashes. Why is this different between devices?
PS: I already solved it, but I want to know why this behaviour...
When in doubt, always check the source code. If you look at MenuItemCompat.java you'll find that it switches based on the API level like so:
static final MenuVersionImpl IMPL;
static {
final int version = android.os.Build.VERSION.SDK_INT;
if (version >= 14) {
IMPL = new IcsMenuVersionImpl();
} else if (version >= 11) {
IMPL = new HoneycombMenuVersionImpl();
} else {
IMPL = new BaseMenuVersionImpl();
}
}
The base setActionView method for the base implementation (which is used for 2.3 devices) just returns the MenuItem, so it wouldn't ever throw the exception:
@Override
public MenuItem setActionView(MenuItem item, View view) {
return item;
}
The HoneycombMenuVersionImpl, on the other hand, delegates to another class:
@Override
public boolean setShowAsAction(MenuItem item, int actionEnum) {
MenuItemCompatHoneycomb.setShowAsAction(item, actionEnum);
return true;
}
And the delegate class attempts to call the actual method on the MenuItem, which will throw an exception:
public static void setShowAsAction(MenuItem item, int actionEnum) {
item.setShowAsAction(actionEnum);
}
In this particular example, checking the source code answers your question and shows you a solid strategy for dealing with compatibility across different versions of Android.