Manish Kumar Sharma
Manish Kumar Sharma

Reputation: 13442

How can there be NullPointerException when there is check for null?

Note: I know that this question is a duplicate and you are probably encouraged to downvote it but,


I recently deployed my APK on playstore and received NullPointerException for a very few users(4):

 Exception java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Object.equals(java.lang.Object)' on a null object reference
android.widget.AdapterView.getPositionForView (AdapterView.java:607)
com.snap.testsnapboard.AlbumSelectActivity$1.onItemClick (AlbumSelectActivity.java:114)
android.widget.AdapterView.performItemClick (AdapterView.java:305)
android.widget.AbsListView.performItemClick (AbsListView.java:1146)
android.widget.AbsListView$PerformClick.run (AbsListView.java:3057)
android.widget.AbsListView.onTouchUp (AbsListView.java:3876)
android.widget.AbsListView.onTouchEvent (AbsListView.java:3641)
android.view.View.dispatchTouchEvent (View.java:8481)
android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2400)
android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2093)
android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2406)
android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2107)
android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2406)
android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2107)
android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2406)
android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2107)
android.view.ViewGroup.dispatchTransformedTouchEvent (ViewGroup.java:2406)
android.view.ViewGroup.dispatchTouchEvent (ViewGroup.java:2107)
com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent (PhoneWindow.java:2369)
com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent (PhoneWindow.java:1719)
android.app.Activity.dispatchTouchEvent (Activity.java:2785)
com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent (PhoneWindow.java:2330)
android.view.View.dispatchPointerEvent (View.java:8676)
android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent (ViewRootImpl.java:4141)
android.view.ViewRootImpl$ViewPostImeInputStage.onProcess (ViewRootImpl.java:4007)
android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562)
android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:3615)
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:3698)
android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589)
android.view.ViewRootImpl$AsyncInputStage.apply (ViewRootImpl.java:3755)
android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562)
android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:3615)
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589)
android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562)
android.view.ViewRootImpl.deliverInputEvent (ViewRootImpl.java:5825)
android.view.ViewRootImpl.doProcessInputEvents (ViewRootImpl.java:5799)
android.view.ViewRootImpl.enqueueInputEvent (ViewRootImpl.java:5770)
android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent (ViewRootImpl.java:5915)
android.view.InputEventReceiver.dispatchInputEvent (InputEventReceiver.java:185)
android.os.MessageQueue.nativePollOnce (MessageQueue.java)
android.os.MessageQueue.next (MessageQueue.java:143)
android.os.Looper.loop (Looper.java:122)
android.app.ActivityThread.main (ActivityThread.java:5254)
java.lang.reflect.Method.invoke (Method.java)
java.lang.reflect.Method.invoke (Method.java:372)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:902)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:697)

This exception originates in the line while ((v = (View) listItem.getParent()) != null && !v.equals(this)) {

in AdapterView.java:

/**
     * Returns the position within the adapter's data set for the view, where
     * view is a an adapter item or a descendant of an adapter item.
     * <p>
     * <strong>Note:</strong> The result of this method only reflects the
     * position of the data bound to <var>view</var> during the most recent
     * layout pass. If the adapter's data set has changed without a subsequent
     * layout pass, the position returned by this method may not match the
     * current position of the data within the adapter.
     *
     * @param view an adapter item, or a descendant of an adapter item. This
     *             must be visible in this AdapterView at the time of the call.
     * @return the position within the adapter's data set of the view, or
     *         {@link #INVALID_POSITION} if the view does not correspond to a
     *         list item (or it is not currently visible)
     */
    public int getPositionForView(View view) {
        View listItem = view;
        try {
            View v;
            while ((v = (View) listItem.getParent()) != null && !v.equals(this)) {
                listItem = v;
            }
        } catch (ClassCastException e) {
            // We made it up to the window without find this list view
            return INVALID_POSITION;
        }

        if (listItem != null) {
            // Search the children for the list item
            final int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                if (getChildAt(i).equals(listItem)) {
                    return mFirstPosition + i;
                }
            }
        }

        // Child not found!
        return INVALID_POSITION;
    }

Other things worth mentioning:

This is the code that ultimately calls the method inside the AdapterView.java. Now, why would there be a NullPointerExceptionwhen there is a null check in the while loop and all the UI processing happens in the main thread only?

Upvotes: 1

Views: 2041

Answers (3)

Tyler Durrant
Tyler Durrant

Reputation: 11

I had to overwrite the method, i just found this question today but i had line 665 and did not see an answer

My best guess is the fix was not in certain API but by importing the method from API 27 and modifying it slightly to pass in the Adapter

public int getPositionForView(View view, AdapterView av)
{
    View listItem = view;
    try
    {
        View v;
        while ((v = (View) listItem.getParent()) != null && !v.equals(av))
        {
            listItem = v;
        }
    }
    catch (ClassCastException e)
    {
        // We made it up to the window without find this list view
        return -1;
    }

    if (listItem != null)
    {
        // Search the children for the list item
        final int childCount = av.getChildCount();
        for (int i = 0; i < childCount; i++)
        {
            if (av.getChildAt(i).equals(listItem))
            {
                return av.getFirstVisiblePosition() + i;
            }
        }
    }

    // Child not found!
    return -1;
}

it always works

Upvotes: 1

Naimatullah
Naimatullah

Reputation: 4079

I want to tell you few tips about null pointer exception.

if listItem is null, it will create exception...if listItem is not null but listItem.getParent() is null, it will also create exception...or either when you cast any object to another and which is null..it throws exception.

(v = (View) listItem.getParent()) != null && !v.equals(this)

In your case, listItem.getParent() is null that's why it throws exception.

you should do like this:

if(v != null && listItem != null && listItem.getParent() != null && (v = (View) listItem.getParent()) != null && !v.equals(this) {

}

I hope it will not throw exception.

Upvotes: 1

piotrpo
piotrpo

Reputation: 12636

If parameter view is null then listItem also will be null. It'll cause NPE here:

listItem.getParent() != null

Upvotes: 0

Related Questions