尝试查找菜单项时应用程序在屏幕旋转时崩溃
App crashes on screen rotation when trying to find menu item
我在我的应用程序中使用了 collapsingToolbarLayout,只要菜单没有折叠,旋转 phone 就没有问题。但是当菜单折叠并且只有原始工具栏显示应用程序崩溃时。问题是,当只有原始工具栏显示时,可点击项目出现并在显示折叠工具栏时消失。旋转 phone 时,应用程序找不到此项。我该如何解决?
菜单所在的 activity。
private Menu menu;
protected void onCreate(Bundle savedInstanceState) {
...
AppBarLayout mAppBarLayout = findViewById(R.id.appBarLayout2);
mAppBarLayout.addOnOffsetChangedListener(new
AppBarLayout.OnOffsetChangedListener() {
int scrollRange = -1;
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int
verticalOffset) {
if (scrollRange == -1) {
scrollRange = appBarLayout.getTotalScrollRange();
}
if (scrollRange + verticalOffset == 0) {
isShow = true;
showOption();
} else if (isShow) {
isShow = false;
hideOption();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
this.menu = menu;
getMenuInflater().inflate(R.menu.menu_scrolling, menu);
hideOption();
return true;
}
private void hideOption() {
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(false);
}
private void showOption() {
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(true);
}
xml-文件中的相关代码:
<android.support.design.widget.AppBarLayout
android:id="@+id/appBarLayout2"
android:layout_width="match_parent"
android:layout_height="128dp"
android:theme="@style/AppTheme.Base"
app:layout_constraintTop_toTopOf="@+id/nestedScrollView">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsTool"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorSecondary"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom|center"
app:expandedTitleMargin="16dp"
app:expandedTitleTextAppearance="@style/TextAppearance.AppCompat.Display2"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:title="@string/title_expenses">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="@drawable/ic_action_exit"
app:title="@string/title_expenses"
app:titleTextColor="@android:color/background_light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
menu_Scrolling.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.journaldev.collapsingtoolbarlayout.ScrollingActivity">
<item
android:id="@+id/action_info"
android:icon="@drawable/ic_action_add"
android:orderInCategory="200"
android:title="Add"
app:showAsAction="ifRoom" />
</menu>
这是错误信息:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.korneliapalm.android.samboappen/com.korneliapalm.android.samboappen.MoneyListActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'android.view.MenuItem android.view.Menu.findItem(int)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3114)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5039)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4948)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'android.view.MenuItem android.view.Menu.findItem(int)' on a null object reference
at com.korneliapalm.android.samboappen.MoneyListActivity.showOption(MoneyListActivity.java:163)
at com.korneliapalm.android.samboappen.MoneyListActivity.onCreate(MoneyListActivity.java:51)
at android.app.Activity.performCreate(Activity.java:7327)
at android.app.Activity.performCreate(Activity.java:7318)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3094)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5039)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4948)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Activity:
当发生方向改变时,android 重新启动 运行 Activity(调用 onDestroy(),然后调用 onCreate())。如果你想在 activity 内部处理,你不能使用:在 manifest 文件中 particular activity.
API12 岁及以下:
android:configChanges="orientation"
如果您的目标是 API 13 岁或以上
android:configChanges="orientation|screenSize"
问题在于,在 onCreate
中,您正在调用方法 hideOption()
和 showOption()
。
但是,oncreate 在 onCreateOptionsMenu
之前被调用,这是您展开菜单视图的地方。所以调用 menu.findItem(R.id.action_info);
会触发一个空指针。
getMenuInflater().inflate(R.menu.menu_scrolling, menu);
在onCreate中调用这两个方法之前,需要确保菜单视图是膨胀的。
private void hideOption() {
if (menu == null) return;
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(false);
}
private void showOption() {
if (menu == null) return;
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(true);
}
您没有在代码中处理方向。您应该尝试处理它们。
崩溃的原因是当您旋转屏幕时发生以下事件:
- Activity 被摧毁。
- Activity 重新创建。
- AppBarLayout 的偏移量发生变化,方法
onOffsetChanged
被调用。
if (scrollRange + verticalOffset == 0) {
条件成立并调用 showOption();
方法。
- 因为正在重新创建 Activity,所以在
showOption();
方法中使用的菜单项是 null
在行 MenuItem item = menu.findItem(R.id.action_info);
- 因为
item
为空,代码 item.setVisible(true);
产生 Null Pointer Exception
. 的运行时崩溃
处理方向的正确方法是在 Activity 代码中实现以下方法:
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks the orientation of the screen
if (newConfig.orientation === Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show()
} else if (newConfig.orientation === Configuration.ORIENTATION_PORTRAIT) {
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show()
}
}
作为预防措施,您可以像这样添加空值检查来暂时避免崩溃:
private void hideOption() {
MenuItem item = menu.findItem(R.id.action_info);
if (item != null) {
item.setVisible(false);
} else {
Log.e("Your Class", "hideOption() was called, but menu item was null");
}
}
private void showOption() {
MenuItem item = menu.findItem(R.id.action_info);
if (item != null) {
item.setVisible(true);
} else {
Log.e("Your Class", "showOption() was called, but menu item was null");
}
}
希望对您有所帮助。
参考link:
https://developer.android.com/guide/topics/resources/runtime-changes
我在我的应用程序中使用了 collapsingToolbarLayout,只要菜单没有折叠,旋转 phone 就没有问题。但是当菜单折叠并且只有原始工具栏显示应用程序崩溃时。问题是,当只有原始工具栏显示时,可点击项目出现并在显示折叠工具栏时消失。旋转 phone 时,应用程序找不到此项。我该如何解决?
菜单所在的 activity。
private Menu menu;
protected void onCreate(Bundle savedInstanceState) {
...
AppBarLayout mAppBarLayout = findViewById(R.id.appBarLayout2);
mAppBarLayout.addOnOffsetChangedListener(new
AppBarLayout.OnOffsetChangedListener() {
int scrollRange = -1;
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int
verticalOffset) {
if (scrollRange == -1) {
scrollRange = appBarLayout.getTotalScrollRange();
}
if (scrollRange + verticalOffset == 0) {
isShow = true;
showOption();
} else if (isShow) {
isShow = false;
hideOption();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
this.menu = menu;
getMenuInflater().inflate(R.menu.menu_scrolling, menu);
hideOption();
return true;
}
private void hideOption() {
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(false);
}
private void showOption() {
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(true);
}
xml-文件中的相关代码:
<android.support.design.widget.AppBarLayout
android:id="@+id/appBarLayout2"
android:layout_width="match_parent"
android:layout_height="128dp"
android:theme="@style/AppTheme.Base"
app:layout_constraintTop_toTopOf="@+id/nestedScrollView">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsTool"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorSecondary"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom|center"
app:expandedTitleMargin="16dp"
app:expandedTitleTextAppearance="@style/TextAppearance.AppCompat.Display2"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:title="@string/title_expenses">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="@drawable/ic_action_exit"
app:title="@string/title_expenses"
app:titleTextColor="@android:color/background_light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
menu_Scrolling.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.journaldev.collapsingtoolbarlayout.ScrollingActivity">
<item
android:id="@+id/action_info"
android:icon="@drawable/ic_action_add"
android:orderInCategory="200"
android:title="Add"
app:showAsAction="ifRoom" />
</menu>
这是错误信息:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.korneliapalm.android.samboappen/com.korneliapalm.android.samboappen.MoneyListActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'android.view.MenuItem android.view.Menu.findItem(int)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3114)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5039)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4948)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'android.view.MenuItem android.view.Menu.findItem(int)' on a null object reference
at com.korneliapalm.android.samboappen.MoneyListActivity.showOption(MoneyListActivity.java:163)
at com.korneliapalm.android.samboappen.MoneyListActivity.onCreate(MoneyListActivity.java:51)
at android.app.Activity.performCreate(Activity.java:7327)
at android.app.Activity.performCreate(Activity.java:7318)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3094)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5039)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4948)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Activity:
当发生方向改变时,android 重新启动 运行 Activity(调用 onDestroy(),然后调用 onCreate())。如果你想在 activity 内部处理,你不能使用:在 manifest 文件中 particular activity.
API12 岁及以下:
android:configChanges="orientation"
如果您的目标是 API 13 岁或以上
android:configChanges="orientation|screenSize"
问题在于,在 onCreate
中,您正在调用方法 hideOption()
和 showOption()
。
但是,oncreate 在 onCreateOptionsMenu
之前被调用,这是您展开菜单视图的地方。所以调用 menu.findItem(R.id.action_info);
会触发一个空指针。
getMenuInflater().inflate(R.menu.menu_scrolling, menu);
在onCreate中调用这两个方法之前,需要确保菜单视图是膨胀的。
private void hideOption() {
if (menu == null) return;
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(false);
}
private void showOption() {
if (menu == null) return;
MenuItem item = menu.findItem(R.id.action_info);
item.setVisible(true);
}
您没有在代码中处理方向。您应该尝试处理它们。 崩溃的原因是当您旋转屏幕时发生以下事件:
- Activity 被摧毁。
- Activity 重新创建。
- AppBarLayout 的偏移量发生变化,方法
onOffsetChanged
被调用。 if (scrollRange + verticalOffset == 0) {
条件成立并调用showOption();
方法。- 因为正在重新创建 Activity,所以在
showOption();
方法中使用的菜单项是null
在行MenuItem item = menu.findItem(R.id.action_info);
- 因为
item
为空,代码item.setVisible(true);
产生Null Pointer Exception
. 的运行时崩溃
处理方向的正确方法是在 Activity 代码中实现以下方法:
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks the orientation of the screen
if (newConfig.orientation === Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show()
} else if (newConfig.orientation === Configuration.ORIENTATION_PORTRAIT) {
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show()
}
}
作为预防措施,您可以像这样添加空值检查来暂时避免崩溃:
private void hideOption() {
MenuItem item = menu.findItem(R.id.action_info);
if (item != null) {
item.setVisible(false);
} else {
Log.e("Your Class", "hideOption() was called, but menu item was null");
}
}
private void showOption() {
MenuItem item = menu.findItem(R.id.action_info);
if (item != null) {
item.setVisible(true);
} else {
Log.e("Your Class", "showOption() was called, but menu item was null");
}
}
希望对您有所帮助。
参考link: https://developer.android.com/guide/topics/resources/runtime-changes