2

I have a gridview, in which i have 24 odd elements.

Ive given the grid a fixed height so scroller appears w.r.t the elements not displayed.

My issue is say given below is my gridview ,where the red line signifies the end of the visible grid and to see below the red line one has to scroll

enter image description here

say i select 6 then scroll and select 22 then again scroll up and select 11 my app crashes with the following error.

Exception is: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference
at com.adamas.ui.AddNewBuyEntryActivity$2.onItemClick(AddNewBuyEntryActivity.java:205)
at android.widget.AdapterView.performItemClick(AdapterView.java:305)
at android.widget.AbsListView.performItemClick(AbsListView.java:1146)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3053)
at android.widget.AbsListView$3.run(AbsListView.java:3860)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5343)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)

if i dont give my grid a fixed height and let it wrap without scroll my app doesnt crash in this scenario.

error occurs at

 ((ImageView) parent.getChildAt(previousSelectedShapePosition).findViewById(R.id.img_sales_shape))
                            .setImageResource(shapeIcons.getResourceId(previousSelectedShapePosition, -1));

code snippet where crash occurs[im using previous position and current position to toggle the colors of selected and previously selected elements]

grdShapes.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            previousSelectedShapePosition = currentSelectedShapePosition;
            currentSelectedShapePosition = position;

            if (spnShape.getSelectedItem().toString().equalsIgnoreCase("Polished")) {
                ((ImageView) view.findViewById(R.id.img_sales_shape)).setImageResource(shapeSelectedIcons.getResourceId(position, 1));

                ((ImageView) parent.getChildAt(previousSelectedShapePosition).findViewById(R.id.img_sales_shape))
                        .setImageResource(shapeIcons.getResourceId(previousSelectedShapePosition, -1));
            } else {
                ((ImageView) view.findViewById(R.id.img_sales_shape)).setImageResource(roughShapeSelected.getResourceId(position, 1));

                ((ImageView) parent.getChildAt(previousSelectedShapePosition).findViewById(R.id.img_sales_shape))
                        .setImageResource(roughShapeIcons.getResourceId(previousSelectedShapePosition, -1));
            }
        }
    });

UPDATE: Spinner code snippet on which basis adapter is set

  spnShape.setOnItemSelectedListener(new OnItemSelectedListener() {

            @Override
            public void onItemSelected(AdapterView<?> parentView, View view, int position, long id) {
                previousSelectedShapePosition = 0;

                if (position == 0) {
                    roughORpolished = 0;
                    adapter = new GridShapeSalesAdapter(AddNewBuyEntryActivity.this, roughShapeItems,roughORpolished);
                    grdShapes.setAdapter(adapter);
                } else if (position == 1) {
                    roughORpolished = 1;
                    adapter = new GridShapeSalesAdapter(AddNewBuyEntryActivity.this, polishedShapeItems,roughORpolished);
                    grdShapes.setAdapter(adapter);
                }


            }

here is my gridview adapter

http://pastebin.com/kaU3UFE5

http://pastebin.com/72Uq94dP

usr30911
  • 2,731
  • 7
  • 26
  • 56
  • getChildAt() method get the view of shown views in the GridView. Your gridview only can contain 20 elements, so if you call getChildAt(22) it will return null since the there are only 20 visible childs in your gridview – Octaviano Putra Feb 22 '16 at 14:04
  • ive debugged and checked the position im passing to getChildAt doesnt exceed the total number of grid items,the crash occurs when i select a item and then scroll down to select a new item while old item is not in view – usr30911 Feb 22 '16 at 14:06
  • It is because the numbers of childs in GridView doesn't always equals to the number of items in your adapter. This condition is caused of 'recycling' behaviour of android adapters. See [link](http://stackoverflow.com/questions/11945563/how-listviews-recycling-mechanism-works) to understand how 'recycling' behaviour works – Octaviano Putra Feb 22 '16 at 14:09

1 Answers1

0

You are trying to get the View which is not visible using

 parent.getChildAt(previousSelectedShapePosition)

When the child is not visible you will get null and as a result NPE.

You need to put some of the logic to getView.

Update

If you select the item change the background of currently selected view, you will have no problem in this. But don't try to change the background of previously selected item if it's not visible. Rather keep a list of position which background needs to be changed when it becomes visible. Use that list as a check in getView and update the background accordingly.

Rohit5k2
  • 17,948
  • 8
  • 45
  • 57
  • sorry for noobishness but logic such as? – usr30911 Feb 22 '16 at 14:25
  • Please see my update. A rough step of how you can do it. – Rohit5k2 Feb 22 '16 at 14:30
  • im still confused,even if i maintain a collection of positions and update it ,i need the previous selected position because im changing the src of the imageview of the previous selected as well as of the current selected – usr30911 Feb 23 '16 at 11:18
  • Change the previously selected view's image in `getView` if it's currently not visible. That's all you need to do. – Rohit5k2 Feb 23 '16 at 11:34
  • you mean to say in my adapter i need to check visibility of view and then set it? currently im doing this in my activity. problem is that i have a spinner ,on spinner change i set the adapter again (see updated code),i think thats causing the issue,by default adapter is set for pos 0,on toggling to postion 1 its set again but i think old instance of adapter is there w.r.t to view – usr30911 Feb 23 '16 at 13:50
  • Its simple. Keep track of items you selected in an array or a list. When you click the item changes its background and removal of background should be done in getView if the view is currently not visible. If its visible change the background there only. – Rohit5k2 Feb 23 '16 at 13:58
  • im not changing background im toggling image src on selection and de selection . so say if its background and i select element 3 i can make all the rest black and element 3 red. but in my case on selecting element 3 the previous elements imageviews src has to be set – usr30911 Feb 23 '16 at 14:03
  • sorry i think im not understanding the issue properly myself,il try out what you suggested thanks – usr30911 Feb 23 '16 at 14:10
  • Correct. change the image src on click of currently selected item. But to unselect you need to check if previously selected item is visible or not. If not then change that in getview. – Rohit5k2 Feb 23 '16 at 14:12