使用AppCompat BottomSheets的NullPointerExeption

时间:2016-03-10 01:47:31

标签: android nullpointerexception material-design android-appcompat appcompat-v7-r23.2

image_id

我在我的活动的onCreate()方法中有这个代码,并且在执行最后一行时我得到了以下的NPE异常:

  

引起:java.lang.NullPointerException:                尝试调用虚方法' java.lang.Object java.lang.ref.WeakReference.get()'在null对象引用上                在android.support.design.widget.BottomSheetBehavior.setState(BottomSheetBehavior.java:440)

5 个答案:

答案 0 :(得分:14)

虽然Sanf0rds的答案是正确的,但它不允许默认情况下将BottomSheet定义为扩展。问题是由于onLayoutChild的最后一行没有设置WeakReference引起的。

解决方案是提供我们自己的类,它扩展了BottomSheetBehavior,但在重写的onLayoutChild中设置状态。代码如下所示。

英国/ AC / QUB / quibe /杂项/ ExpandedBottomSheetBehavior.java

package uk.ac.qub.quibe.misc;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by mcp on 15/03/16.
 */
public class ExpandedBottomSheetBehavior<V extends View> extends android.support.design.widget.BottomSheetBehavior<V> {

    public ExpandedBottomSheetBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onLayoutChild(final CoordinatorLayout parent, final V child, final int layoutDirection) {
        SavedState dummySavedState = new SavedState(super.onSaveInstanceState(parent, child), STATE_EXPANDED);
        super.onRestoreInstanceState(parent, child, dummySavedState);
        return super.onLayoutChild(parent, child, layoutDirection);
        /*
            Unfortunately its not good enough to just call setState(STATE_EXPANDED); after super.onLayoutChild
            The reason is that an animation plays after calling setState. This can cause some graphical issues with other layouts
            Instead we need to use setInternalState, however this is a private method.
            The trick is to utilise onRestoreInstance to call setInternalState immediately and indirectly
         */
    }

}

在布局文件参考中引用您的新自定义行为。

更改

app:layout_behavior="android.support.design.widget.BottomSheetBehavior"

app:layout_behavior="uk.ac.qub.quibe.misc.ExpandedBottomSheetBehavior"

答案 1 :(得分:4)

public class ExpandedBottomSheetBehavior<V extends View> extends
    android.support.design.widget.BottomSheetBehavior<V> {

  public ExpandedBottomSheetBehavior(Context context, AttributeSet attrs) {
    super(context, attrs);
}

  @Override
  public boolean onLayoutChild(final CoordinatorLayout parent, final V child, final int layoutDirection) {
    return super.onLayoutChild(parent, child, layoutDirection);
  }

  @Override
  public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
    try {
      return super.onInterceptTouchEvent(parent, child, event);
    } catch (NullPointerException ignored) {
      return false;
    }
  }
}

答案 2 :(得分:2)

您的代码的问题是您尝试直接在onCreate中调用setState方法。这将抛出一个nullPointer,因为WeakReference尚未初始化。当协调器布局即将放置其子视图时,它将被初始化。

  

onLayoutChild(CoordinatorLayout parent,V child,int layoutDirection)

     

当父级CoordinatorLayout关于布局时调用   给予孩子观点。

因此,最佳方法是将peek height设置为0并在onItemClick侦听器中显示/隐藏。

我在这里回答了这个问题: https://stackoverflow.com/a/36236743/1314796

答案 3 :(得分:1)

我找到了一个解决方案,但我仍然不知道为什么会这样。在活动运行后,解决方案将最后一行放在用户调用中。例如:在contextMenu回调或任何OnClickListener中。

答案 4 :(得分:1)

您还可以考虑收听全局布局事件,这样您就可以确保在设置折叠状态时已经布置了底片。

final View bottomSheet = findViewById(R.id.bottom_sheet);
bottomSheet.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            bottomSheet.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
            bottomSheetBehavior.setPeekHeight(300);
            bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
        }
    });