当检查为null时,怎么会有NullPointerException?

时间:2017-08-11 08:36:59

标签: android nullpointerexception

注意:我知道这个问题是重复的,您可能会被鼓励低估,但是,

  • 它发生在Android Framework代码
  • 即使存在空检查且没有多线程,也会发生这种情况。

我最近在Playstore上部署了我的APK,并为少数用户(4)收到了NullPointerException

 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)

此异常源自行while ((v = (View) listItem.getParent()) != null && !v.equals(this)) {

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;
    }

其他值得一提的事情:

  • 我有一个列表视图,它通过addFooterView()
  • 附加了一个页脚视图
  • 我想检查这个页脚视图是否已被点击并且什么都不做,因为这个视图只包含一些不是通常列表项的图形。
  • 为此,我写了以下代码:

                // Since we have a Footer view attached to the ListView, the position selected
                // might not always map 1-to-1 with the ArrayList we are using to represent the
                // Album model objects list. Lets check if the Footer view has been selected and
                // in this case, do nothing.
    
                if(myListView.getPositionForView(loadMoreView) == arg2){
                    // Blank return
                    return;
                }
    

这是最终在AdapterView.java内调用方法的代码。现在,为什么在while循环中存在空检查并且所有UI处理仅在主线程中发生时会有NullPointerException

2 个答案:

答案 0 :(得分:1)

我想告诉你一些关于空指针异常的提示。

如果listItem为null,它将创建异常...如果listItem不为null但listItem.getParent()为null,它也将创建异常...或者当您将任何对象转换为另一个对象时为null ..引发异常。

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

在你的情况下,listItem.getParent()为null,这就是它抛出异常的原因。

你应该这样做:

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

}

我希望它不会抛出异常。

答案 1 :(得分:1)

我不得不覆盖这个方法,我今天才发现这个问题,但我有665行并没有看到答案

我最好的猜测是修复不在某些API中,而是从API 27导入方法并稍微修改它以传递适配器

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;
}

它始终有效