Android BottomSheetBehavior setState() NullPointerException
Android BottomSheetBehavior setState() NullPointerException
我正在尝试从 Android 支持设计库实施 BottomSheetBehavior
。我这样初始化 BottomSheetBehavior
:
private void initBottomSheet() {
new AsyncTask<Void, Void, Void>() {
View bottomSheetFrame = rootView.findViewById(R.id.bottom_sheet);
}
@Override
protected Void doInBackground(Void... params) {
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetFrame);
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
private boolean isOnTop = false;
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
switch (newState) {
case BottomSheetBehavior.STATE_DRAGGING: {
...
}
case BottomSheetBehavior.STATE_SETTLING: {
...
}
case BottomSheetBehavior.STATE_EXPANDED: {
...
}
case BottomSheetBehavior.STATE_COLLAPSED: {
...
}
case BottomSheetBehavior.STATE_HIDDEN: {
...
}
default: {
break;
}
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
...
});
bottomSheetBehavior.setPeekHeight((int) Utils.convertDpToPixel(100f, activityContext));
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); // NPE here
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}.execute();
}
这很奇怪,因为我可以通过 Button
单击或其他一些操作来更改状态。请帮帮我。
问题
NPE 发生是因为您在视图 bottomSheetFrame
布局之前调用了 BottomSheetBehavior.setState(...)
。此时 BottomSheetBehavior 对视图有 null
引用,无法将您的状态应用到它。
解决方案
我使用 View.post(Runnable)
方法解决了这个问题:
View sheetView = ... ;
BottomSheetBehavior behavior = BottomSheetBehavior.from(sheetView);
int initState = BottomSheetBehavior.STATE_EXPANDED;
sheetView.post(new Runnable() {
@Override
public void run() {
behavior.setState(initState);
}
});
在我的情况下,这有助于阻止 NPE-s :)
如果您在 Fragment
中使用它,请确保在 onCreateView()
方法中调用它。如果您在 Activity
上使用它,则在 onCreate()
方法中调用它。
此时,您的视图必须已经创建,除非您以编程方式创建它们。
由于您正在从 AsyncTask
调用与 UI 相关的方法,因此您需要用 runOnUiThread
将其包围起来,如此处所述
基本上,您需要从应用程序的主线程(即 UI 线程)调用与视图相关的任何内容。
我正在尝试从 Android 支持设计库实施 BottomSheetBehavior
。我这样初始化 BottomSheetBehavior
:
private void initBottomSheet() {
new AsyncTask<Void, Void, Void>() {
View bottomSheetFrame = rootView.findViewById(R.id.bottom_sheet);
}
@Override
protected Void doInBackground(Void... params) {
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetFrame);
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
private boolean isOnTop = false;
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
switch (newState) {
case BottomSheetBehavior.STATE_DRAGGING: {
...
}
case BottomSheetBehavior.STATE_SETTLING: {
...
}
case BottomSheetBehavior.STATE_EXPANDED: {
...
}
case BottomSheetBehavior.STATE_COLLAPSED: {
...
}
case BottomSheetBehavior.STATE_HIDDEN: {
...
}
default: {
break;
}
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
...
});
bottomSheetBehavior.setPeekHeight((int) Utils.convertDpToPixel(100f, activityContext));
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); // NPE here
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}.execute();
}
这很奇怪,因为我可以通过 Button
单击或其他一些操作来更改状态。请帮帮我。
问题
NPE 发生是因为您在视图 bottomSheetFrame
布局之前调用了 BottomSheetBehavior.setState(...)
。此时 BottomSheetBehavior 对视图有 null
引用,无法将您的状态应用到它。
解决方案
我使用 View.post(Runnable)
方法解决了这个问题:
View sheetView = ... ;
BottomSheetBehavior behavior = BottomSheetBehavior.from(sheetView);
int initState = BottomSheetBehavior.STATE_EXPANDED;
sheetView.post(new Runnable() {
@Override
public void run() {
behavior.setState(initState);
}
});
在我的情况下,这有助于阻止 NPE-s :)
如果您在 Fragment
中使用它,请确保在 onCreateView()
方法中调用它。如果您在 Activity
上使用它,则在 onCreate()
方法中调用它。
此时,您的视图必须已经创建,除非您以编程方式创建它们。
由于您正在从 AsyncTask
调用与 UI 相关的方法,因此您需要用 runOnUiThread
将其包围起来,如此处所述
基本上,您需要从应用程序的主线程(即 UI 线程)调用与视图相关的任何内容。