简体   繁体   English

尝试查找菜单项时,应用程序在屏幕旋转时崩溃

[英]App crashes on screen rotation when trying to find menu item

I am using a collapsingToolbarLayout in my application and as long as the menu is not collapsed there is no problem when rotating the phone. 我在应用程序中使用collapsingToolbarLayout,并且只要不折叠菜单,旋转手机时就不会出现问题。 But when the menu is collapsed and only the original toolbar is showing the app crashes. 但是,当菜单折叠时,只有原始工具栏显示应用程序崩溃。 The thing is, when only the original toolbar is showing a clickable item appears and disappears when the collapsing toolbar is shown. 事实是,当仅显示原始工具栏时,当显示折叠的工具栏时,可单击项就会出现并消失。 When rotating the phone, the application does not find this item. 旋转手机时,应用程序找不到此项目。 How can I solve this? 我该如何解决?

The activity where the menu is. 菜单所在的活动。

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

The relevant code in xml-file: 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>

The menu_Scrolling.xml 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>

This is the error message: 这是错误消息:

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) 

The problem is that in onCreate you are calling the methods hideOption() and showOption() . 问题在于,在onCreate您正在调用方法hideOption()showOption() However, oncreate is called before onCreateOptionsMenu which is where you are inflating the menu view. 但是,oncreate在onCreateOptionsMenu之前被调用,这是您要放大菜单视图的位置。 So calling menu.findItem(R.id.action_info); 因此调用menu.findItem(R.id.action_info); triggers a null pointer. 触发一个空指针。

getMenuInflater().inflate(R.menu.menu_scrolling, menu);

You need to ensure that the menu view is inflated before you call these two methods in onCreate. 在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: 活动:

When orientation change occurs,android restarts the running Activity ( onDestroy() is called, followed by onCreate()). 发生方向变化时,android重新启动正在运行的Activity(先调用onDestroy(),再调用onCreate())。 If you want to handle inside activity,you cant use: in manifest file for particular activity. 如果要处理内部活动,则不能在清单文件中使用:进行特定活动。

For API 12 and below: 对于API 12及以下版本:

android:configChanges="orientation"

if you are targeting API 13 or above 如果您定位的是API 13或更高版本

android:configChanges="orientation|screenSize"

You have not handled orientations in your code. 您尚未在代码中处理方向。 You should try to handle them. 您应该尝试处理它们。 The reason for your crash is that when you rotate your screen following event happens: 崩溃的原因是,当您旋转屏幕时,发生以下事件:

  1. Activity gets destroyed. 活动被破坏。
  2. Activity gets re-created. 活动被重新创建。
  3. AppBarLayout's offset gets changed and the method onOffsetChanged is called. AppBarLayout的偏移量将更改,并调用onOffsetChanged方法。
  4. if (scrollRange + verticalOffset == 0) { condition gets true and showOption(); if (scrollRange + verticalOffset == 0) {条件为真,并且showOption(); method is called. 方法被调用。
  5. Because the Activity is being re-created, the menu item that is used in showOption(); 由于正在重新创建活动,因此showOption();使用的菜单项showOption(); method is null on the line MenuItem item = menu.findItem(R.id.action_info); MenuItem item = menu.findItem(R.id.action_info);行上,方法为null MenuItem item = menu.findItem(R.id.action_info);
  6. Because the item is null, the code item.setVisible(true); 由于item为空,则代码item.setVisible(true); produces a runtime crash of Null Pointer Exception . 产生Null Pointer Exception运行时崩溃。

The proper way of handling orientations is to implement the following method in your Activity code: 处理方向的正确方法是在“活动”代码中实现以下方法:

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()
    }
}

As a pre-cautionary measure, you can add null checks for avoiding the crashes temporarily like this: 作为一种预防措施,您可以添加空值检查来避免临时崩溃,如下所示:

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

I hope this helps. 我希望这有帮助。

Reference link: https://developer.android.com/guide/topics/resources/runtime-changes 参考链接: https : //developer.android.com/guide/topics/resources/runtime-changes

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我的应用程序崩溃,尝试添加菜单 - My app crashes, trying to add a menu 应用程序在轮换时崩溃,NullPointerException - App crashes on rotation, NullPointerException 代码的旋转屏幕在AsyncTask中崩溃 - Rotation screen by code crashes in AsyncTask 我正在尝试从我的 HomeActivity 扩展菜单,但是当我单击列表中的任何项目时应用程序崩溃 - I am trying to inflate a menu from my HomeActivity but the app crashes when i click any of the items on the list 我的应用程序正在运行,但屏幕为黑色,并在尝试使用自定义视图时崩溃 - My app is running but the screen is black, and crashes when trying to use a custom view 旋转屏幕后尝试从活动中接收响应时,Android应用程序崩溃 - Android app crashes when trying to receive a response from an activity after the screen has been rotated 初始屏幕后,应用程序崩溃(应显示菜单屏幕时) - The application crashes after the splash screen (When the menu screen supposed to appear) 停止录制屏幕时应用程序崩溃 - The app crashes when you stop recording screen 按下Navigaiton抽屉项目时应用崩溃 - App Crashes When Navigaiton Drawer Item is Pressed 尝试在线程中显示AlertDialog时,应用崩溃 - App crashes when trying to show AlertDialog in thread
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM