Android’s onCreateContextMenu() called with no ContextMenuInfo

I recently had an exception report from an eeePC using a mouse which caused the following code to give a NullPointerException:

public void onCreateContextMenu(ContextMenu aMenu, View aView, ContextMenuInfo aMenuInfo) {
	AdapterView.AdapterContextMenuInfo theMenuInfo = null;
	try {
		theMenuInfo = (AdapterView.AdapterContextMenuInfo) aMenuInfo;
	} catch (ClassCastException e) {
		return;
	}
	File theFile = myActivity.getListItem(theMenuInfo.position);
	//...snip rest of code...
}{/java]
The only way that theMenuInfo would be NULL in order to cause the NullPointerException is that the passed in aMenuInfo was NULL -- and that is not supposed to be the case.

I am not quite sure how such an event occurred. It could be a result of "right-clicking" on a spot where there is no list item shown, except that the behavior in that case should have not resulted in a context menu since there is no item there at all. While I should not have to protect my code against a NULL being passed in for the required ContextMenuInfo parameter, I have to live in the world that <em>is</em>, not the world of <em>should</em>. Who knows, maybe this is the start of a trend where "right clicking" on the "white space" of a list will pass in NULL for that parameter and cause a completely different menu to popup for quick actions that provide the same functionality as clicking on the Menu button and choosing some deeper submenu from that list. Then again, it is probably just a bug in the OS and will be fixed at a later point in time. Either way, it's best to protect against NULL parameters even if they should never be NULL.

My new code:
[java]public void onCreateContextMenu(ContextMenu aMenu, View aView, ContextMenuInfo aMenuInfo) {
	AdapterView.AdapterContextMenuInfo theMenuInfo = null;
	File theFile = null;
	try {
		theMenuInfo = (AdapterView.AdapterContextMenuInfo) aMenuInfo;
		theFile = myActivity.getListItem(theMenuInfo.position);
	} catch (ClassCastException cce) {
		return;
	} catch (NullPointerException npe) {
		return;
	}
	//...snip rest of code...
}

If you know why the ContextMenuInfo parameter is sometimes NULL, please feel free to share the reason as I know several developers that would be interested in it besides myself.

Android: Proof that findViewById() is slower than using a ViewHolder

I was recently asked to provide proof of why using a ViewHolder would be faster than just using findViewById() when populating the item views of each item in a ListView. A fair question since empirically stating “it seems faster” is hardly proof and my results may have been from other factors I had not thought of at the time. So, I delved into the Android source code and pulled a bit of research together to present proof Continue reading

Android Dialogs and onContextItemSelected()

ListViews and GridViews are great widgets to use in an Activity for your app. Sometimes it is useful to also create smaller versions of them for dialogs within your app. There’s only one problem: Context Menus. If you have tried to put a context menu on a ListView inside a dialog, you may have found out that while onCreateContextMenu() is called, onContextItemSelected() is not. There is a workaround, though, because onContextItemSelected() is actually a convenience method called from onMenuItemSelected(int, MenuItem). If you add the following method to your dialog containing the ListView (or GridView), you will find that onContextItemSelected() is working again.

@Override
public boolean onMenuItemSelected(int aFeatureId, MenuItem aMenuItem) {
    if (aFeatureId==Window.FEATURE_CONTEXT_MENU)
        return onContextItemSelected(aMenuItem);
    else
        return super.onMenuItemSelected(aFeatureId, aMenuItem);
}

 

Android ListView and setSelection

Android’s ListView is a powerful class that is capable of presenting a list of whatever you wish fairly easily. One of the issues that has vexed me has been scrolling the ListView to a particular entry. While newer Android versions have provided better support in this area, trying to maintain backward compatibility with Android 1.5 presents some challenges. In light of this Google issue and it’s comments, I have come up with a decent method of scrolling a ListView to a particular position if it is not already visible. I clear the focus after setting the selection because users became confused at why an “orange box suddenly appeared” when they did not expressly tap a selection with their finger or scroll with the trackball.

//this method would be part of a ListView class
    @Override
    public void scrollToPosition(final int anItemPos) {
        if (anItemPos!=AdapterView.INVALID_POSITION) {
            int theFirstItemPos = getFirstVisibleItemPos();
            int theLastItemPos = getLastVisibleItemPos();
            if (anItemPos&lt;theFirstItemPos || theLastItemPos&lt;anItemPos) {
                getListView().post(new Runnable() {
                    @Override
                    public void run() {
                        getListView().setSelection(anItemPos);
                        getListView().clearFocus();
                    }    
                });
            }
        }
    }

findViewById slow inside ListView adapters

I was reading an article over on charlie.collins’s blog about using a ViewHolder class to cache the results of a findViewById() when used inside the getView() of a list’s adapter. I gave his recommendation a try and I did notice a speed improvement in my app so the observation that findViewById() is a performance hit has enough merit to go out of your way to enable some kind of caching mechanism.

While Charlie went the route of creating a class to hold the various views he was interested in, I decided to take a slightly different approach and make use of the alternative setTag(int, Object) function instead. Continue reading

Using a SubMenu in a ListActivity’s Context Menu

One of the limitations of Android’s ListActivity’s Context Menu is that if your context menu gets too large to fit comfortably into one list, shortening it by putting several items into SubMenus requires special handling in onContextItemSelected().

Context menus, by definition, are transient and will be thrown away as soon as they disappear from view. Once you click on a MenuItem that displays a SubMenu, clicking any item in that SubMenu will call the onContextItemSelected(), as expected. What is not expected is that the standard call to get the MenuInfo will return null. Continue reading