React-native-picker-select: [Android] FATAL EXCEPTION java.lang.ArrayIndexOutOfBoundsException

Created on 31 Jul 2019  Â·  16Comments  Â·  Source: lawnstarter/react-native-picker-select

The Android app is crashing when reseting items and value at the same time.

In my app I have 3 dropdown which depend on each other, every time I try change the value from the first, I need to reset the items and value of the 2 others, and when that happen on Android the app crashed right away.

Expected behavior

By clearing the items array and the value, the picker should display the picker without any items.

Smartphone (please complete the following information):

  • Device: All of them
  • OS: Android
  • react-native-picker-select version: 6.3.0
  • react-native version: 0.60.4
  • react version: 16.8.6

Logs

07-30 17:30:34.390  E   unknown ReactNative: Exception in native call   
07-30 17:30:34.390  E   unknown ReactNative: java.lang.ArrayIndexOutOfBoundsException: length=2; index=2    
07-30 17:30:34.390  E   unknown ReactNative:    at java.util.Arrays$ArrayList.get(Arrays.java:3769) 
07-30 17:30:34.390  E   unknown ReactNative:    at android.widget.ArrayAdapter.getItem(ArrayAdapter.java:393)   
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.views.picker.ReactPickerManager$ReactPickerAdapter.getView(ReactPickerManager.java:116)   
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.views.picker.ReactPickerManager$ReactPickerAdapter.getView(ReactPickerManager.java:107)   
07-30 17:30:34.390  E   unknown ReactNative:    at android.widget.Spinner.makeView(Spinner.java:712)    
07-30 17:30:34.390  E   unknown ReactNative:    at android.widget.Spinner.layout(Spinner.java:660)  
07-30 17:30:34.390  E   unknown ReactNative:    at android.widget.AbsSpinner.setSelectionInt(AbsSpinner.java:306)   
07-30 17:30:34.390  E   unknown ReactNative:    at android.widget.AbsSpinner.setSelection(AbsSpinner.java:283)  
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.views.picker.ReactPicker.commitStagedData(ReactPicker.java:142)   
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.views.picker.ReactPickerManager.onAfterUpdateTransaction(ReactPickerManager.java:80)  
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.views.picker.ReactPickerManager.onAfterUpdateTransaction(ReactPickerManager.java:36)  
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.uimanager.ViewManager.updateProperties(ViewManager.java:47)   
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.uimanager.NativeViewHierarchyManager.updateProperties(NativeViewHierarchyManager.java:139)    
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.uimanager.UIViewOperationQueue$UpdatePropertiesOperation.execute(UIViewOperationQueue.java:93)    
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:844)   
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:952) 
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.uimanager.UIViewOperationQueue.access$2200(UIViewOperationQueue.java:44)  
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:1012) 
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)  
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:172) 
07-30 17:30:34.390  E   unknown ReactNative:    at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:84) 
07-30 17:30:34.390  E   unknown ReactNative:    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:947)    
07-30 17:30:34.390  E   unknown ReactNative:    at android.view.Choreographer.doCallbacks(Choreographer.java:761)   
07-30 17:30:34.390  E   unknown ReactNative:    at android.view.Choreographer.doFrame(Choreographer.java:693)   
07-30 17:30:34.390  E   unknown ReactNative:    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935) 
07-30 17:30:34.390  E   unknown ReactNative:    at android.os.Handler.handleCallback(Handler.java:873)  
07-30 17:30:34.390  E   unknown ReactNative:    at android.os.Handler.dispatchMessage(Handler.java:99)  
07-30 17:30:34.390  E   unknown ReactNative:    at android.os.Looper.loop(Looper.java:193)  
07-30 17:30:34.390  E   unknown ReactNative:    at android.app.ActivityThread.main(ActivityThread.java:6669)    
07-30 17:30:34.390  E   unknown ReactNative:    at java.lang.reflect.Method.invoke(Native Method)   
07-30 17:30:34.390  E   unknown ReactNative:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)    
07-30 17:30:34.390  E   unknown ReactNative:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
07-30 17:30:34.393  D   AndroidRuntime   Shutting down VM   
07-30 17:30:34.393  E   AndroidRuntime   FATAL EXCEPTION: main  
07-30 17:30:34.393  E   AndroidRuntime   java.lang.ArrayIndexOutOfBoundsException: length=2; index=2    
07-30 17:30:34.393  E   AndroidRuntime      at java.util.Arrays$ArrayList.get(Arrays.java:3769) 
07-30 17:30:34.393  E   AndroidRuntime      at android.widget.ArrayAdapter.getItem(ArrayAdapter.java:393)   
07-30 17:30:34.393  E   AndroidRuntime      at com.facebook.react.views.picker.ReactPickerManager$ReactPickerAdapter.getView(ReactPickerManager.java:116)   
07-30 17:30:34.393  E   AndroidRuntime      at com.facebook.react.views.picker.ReactPickerManager$ReactPickerAdapter.getView(ReactPickerManager.java:107)   
07-30 17:30:34.393  E   AndroidRuntime      at android.widget.Spinner.makeView(Spinner.java:712)    
07-30 17:30:34.393  E   AndroidRuntime      at android.widget.Spinner.layout(Spinner.java:660)  
07-30 17:30:34.393  E   AndroidRuntime      at android.widget.Spinner.onLayout(Spinner.java:622)    
07-30 17:30:34.393  E   AndroidRuntime      at com.facebook.react.views.picker.ReactPicker.onLayout(ReactPicker.java:98)    
07-30 17:30:34.393  E   AndroidRuntime      at android.view.View.layout(View.java:20672)    
07-30 17:30:34.393  E   AndroidRuntime      at android.view.ViewGroup.layout(ViewGroup.java:6194)   
07-30 17:30:34.393  E   AndroidRuntime      at com.facebook.react.views.picker.ReactPicker$2.run(ReactPicker.java:81)   
07-30 17:30:34.393  E   AndroidRuntime      at android.os.Handler.handleCallback(Handler.java:873)  
07-30 17:30:34.393  E   AndroidRuntime      at android.os.Handler.dispatchMessage(Handler.java:99)  
07-30 17:30:34.393  E   AndroidRuntime      at android.os.Looper.loop(Looper.java:193)  
07-30 17:30:34.393  E   AndroidRuntime      at android.app.ActivityThread.main(ActivityThread.java:6669)    
07-30 17:30:34.393  E   AndroidRuntime      at java.lang.reflect.Method.invoke(Native Method)   
07-30 17:30:34.393  E   AndroidRuntime      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)    
07-30 17:30:34.393  E   AndroidRuntime      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
help wanted

Most helpful comment

Workaround Solution

Someone on my team found another solution to this problem - you can pass key={items.length} to this component which will causes it to remount on render when the items.length changes.

All 16 comments

Fill out the entire bug report

I'm also experiencing this on Android rn 0.60.4 only in release bundle

Screenshot 2019-08-06 09 05 00

@lfkwtz can this be re-opened? I won't open a new issue/bug since i don't have reproducible steps - we're only seeing this come through our Sentry error reporting randomly without any rhyme or reason. I've attached the screenshot from native stack trace above.

@crobinson42 sure i'll reopen it for a while - maybe someone can share some code that will reproduce this.

Here's my component that uses this lib where the native error is being thrown:

````
import React from 'react'
import PropTypes from 'prop-types'
import { View } from 'react-native'
import { Input } from 'react-native-elements'
import Select from 'react-native-picker-select'
import { useSelector } from 'react-redux'

function DepartmentPicker(props) {
const departments = useSelector(state => state.site.departments)

const handleChange = option => {
if (props.onChange) props.onChange(option)
}

const deptItems = departments.map(({ departmentId, name }) => ({
label: name,
value: departmentId,
}))
const inputValue = (deptItems.find(item => item.value === props.value) || {})
.label

return (

disabled={props.disabled}
items={deptItems}
onValueChange={handleChange}
placeholder={{
label: 'Select Department',
value: null,
}}
value={props.value}
>
editable={false}
placeholder='Department'
rightIcon={{
color: SSCS_GREY_LIGHTENED,
containerStyle: { paddingRight: 10 },
name: 'caretdown',
type: 'antdesign',
}}
inputStyle={props.inputStyle}
value={inputValue}
/>


)
}
```

Solved

The problem for us is the items list is dynamic in our component. When we explicitly pass value to react-native-picker-select and the items list is updated from some external user action to a new items list, react-native-picker-select's internal state of the index of the last value is passed to the native react-native picker component of an index that no longer exists in the items list.

@lfkwtz there should be a small change in the underlying logic for the react-native-picker-select component to always verify that the index exists in props.items before passing it to react-native picker to prevent this from happening in the future.

Solved

The problem for us is the items list is dynamic in our component. When we explicitly pass value to react-native-picker-select and the items list is updated from some external user action to a new items list, react-native-picker-select's internal state of the index of the last value is passed to the native react-native picker component of an index that no longer exists in the items list.

@lfkwtz there should be a small change in the underlying logic for the react-native-picker-select component to always verify that the index exists in props.items before passing it to react-native picker to prevent this from happening in the future.

That's exactly the same thing that was happening for me, but I was looking at react-native-picker-select code to see how they deal with this, and it seems to be handling it correctly, so I think it might be related with the way RN Android Picker handles items changes itself.

did this issue just crop up recently for either of you after updating RN? since you're both on 0.60.4 and I haven't seen this bug before...

I only recently started using this lib. We haven’t experienced the same issue in the last 2 years before when we used the native component.

Sent from my iPhone

On Aug 6, 2019, at 11:06 AM, Michael Lefkowitz notifications@github.com wrote:

did this issue just crop up recently for either of you after updating RN? since you're both on 0.60.4 and I haven't seen this bug before...

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

@lfkwtz In my case, I've been using this library for over a year, and never had this issue before. I didn't notice it when I first did the RN upgrade to 0.60.0, because it doesn't crash right away, you have to be updating the picker in order for it to crash on Android. iOS has worked for me just fine. Noticed on 0.60.4, because is where an actual user reported it, so I did the research about it and found this.

I was able to consistently reproduce this with 2 picker components on a screen at the same time where PickerA's selected item determines PickerB's items to render.

When PickerB has a selected item who's item's list index is say 10, then PickerA's selected item is changed and PickerB's items prop is changed and does not contain an index of 10, the ArrayIndexOutOfBoundsException will throw in the native code.

High level (opinion) this component should be refactored to get rid of getDerivedStateFromProps() because the current logic/order is causing the selectedValue passed to the react-native Picker component to get out of sync with the items list from props that are passed in. In other words, when this components items list is updated, they are rendered and passed to react-native's Picker component with selectedValue of the previous items list in the last render.

Cool - will check out the pr soon. The eventual plan is to split off into named exports so I can make this a controlled component to fix #112 and in general make the component a little more dumb - but still have the 'legacy' export too. But in the near term, having some additional checks in there to prevent bugs like this is fine with me.

Workaround Solution

Someone on my team found another solution to this problem - you can pass key={items.length} to this component which will causes it to remount on render when the items.length changes.

Workaround Solution

Someone on my team found another solution to this problem - you can pass key={items.length} to this component which will causes it to remount on render when the items.length changes.

it works, thank you

i'm going to close this out since it is an upstream issue https://github.com/facebook/react-native/issues/26406

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dkniffin picture dkniffin  Â·  3Comments

dakairus picture dakairus  Â·  3Comments

Friendly-Robot picture Friendly-Robot  Â·  5Comments

Unforgiven-wanda picture Unforgiven-wanda  Â·  4Comments

dquessenberry picture dquessenberry  Â·  7Comments