Search code examples
javaandroiddynamiclistenerandroid-gridlayout

Android app crashing on method call from menu item


I have a function called createGrid that crates a grid of buttons in a Gridlayout (code below), sets their listener and adds a custom layout called no_padding_button to each one.

after creating the grid, depending on what button(s) the user has clicked on I have another function called saveDesign that iterates through the gridlayout and returns the number of clicked buttons depending on their tag. I call saveDesign from a menu Item.

The problem is that as soon as I called the saveDesign method, the app crashes. The grid works fine, you click buttons, they change color and their tag changes but some reason trying to read through the gridlayout crashes the app.

can you guys help me understand what the error in my code is?

Thanks

//method to create a new grid, the number of rows and columns come from the dialogue inside the activity and then passed to this function
void createGrid(final Context context, GridLayout gridLayout) {

    gridLayout.setColumnCount(totalColumns);    //set the number of rows of the gridlayout
    gridLayout.setRowCount(totalRows);          //set the number of columns of the grid layout

    //add the buttons and implement their listeners
    for (int i = 0; i < totalRows; i++) {
        for (int j = 0; j < totalColumns; j++) {
            Button button = new Button(context);
            //no padding
            button.setBackground(context.getResources().getDrawable(R.drawable.no_padding_button));
            //set the name of the button according to its position
            button.setText(Integer.toString(i) + "," + Integer.toString(j)+",");
            //hide the name, the user does not need to see this information at this moment
            button.setTextColor(View.INVISIBLE);

            //setting up the layout parameters for each button
            GridLayout.LayoutParams param = new GridLayout.LayoutParams();
            param.setMargins(0, 0, 0, 0);
            button.setLayoutParams(param);

            //button listener
            button.setOnClickListener(new View.OnClickListener() {
                boolean already_clicked = false;
                @Override
                public void onClick(View v) {

                    //on click, hide the button
                    Button button = (Button) v;
                    if(!already_clicked){
                    //change the color of the selected buttons as an indication
                    button.setBackgroundColor(context.getResources().getColor(R.color.selected_button));
                        button.setTag(1);
                        already_clicked =true;
                    }
                    else{
                        button.setBackgroundColor(context.getResources().getColor(R.color.unselected_button));
                        button.setTag(0);
                        already_clicked =false;
                    }
                }
            });

            gridLayout.addView(button);
        }
    }

    Toast.makeText(context, "Grid Created", Toast.LENGTH_SHORT).show();
}

saveDesing method:

public void saveDesign(){
    int temp=0;
    for (int i=0;i<gridLayout.getChildCount(); i++){
        Button childButton = (Button)gridLayout.getChildAt(i);
        if(childButton.getTag().toString() == "1"){
            temp++;
        }
    }
    Toast.makeText(this, Integer.toString(temp), Toast.LENGTH_SHORT).show();
}

the xml code of the activity holding the gridlayout:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center">
    <HorizontalScrollView android:id="@+id/HorizontalScrollView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center">
        <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/gridLayout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center">

        </GridLayout>
    </HorizontalScrollView>
</ScrollView>

UPDATE 1 the error log , i also tried string.equals("1") but i got the same error:

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.example.test.gridtest, PID: 3247
                  java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Object.equals(java.lang.Object)' on a null object reference
                      at com.example.abtin.gridtest.MainActivity.saveDesign(MainActivity.java:85)
                      at com.example.abtin.gridtest.MainActivity.onOptionsItemSelected(MainActivity.java:109)
                      at android.app.Activity.onMenuItemSelected(Activity.java:3204)
                      at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:406)
                      at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:195)
                      at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:103)
                      at android.support.v7.app.AppCompatDelegateImplV9.onMenuItemSelected(AppCompatDelegateImplV9.java:667)
                      at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:810)
                      at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
                      at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:957)
                      at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:947)
                      at android.support.v7.widget.ActionMenuView.invokeItem(ActionMenuView.java:616)
                      at android.support.v7.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:153)
                      at android.view.View.performClick(View.java:5610)
                      at android.view.View$PerformClick.run(View.java:22260)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6077)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

Solution

  • If you don't click on button, it haven't tag. Therefore childButton.getTag() return null and toString crash your app. So check in saveDesign()

    if(childButton.getTag() != null) {
        if(childButton.getTag().toString() == "1"){
            temp++;
        }
    }
    

    or set button tag when create button.