Sometimes Android crashes as reported by Crashlytics are not that easy to solve - at least the first time you encounter something you haven't thought of before - and often they are not even reproducable easily or always. The more active installs your app has, the more "weird" issues you will encounter, as there will be more constellations that could cause an error but one that will not always happens.
Have a look at the following example:
Looks nice, right? Nice-looking code can't be buggy? Or can it?
Yes it can!
What happens if videoListContent changes? In this case the changes would not be reported back to the RecyclerView...in this case we could fix it, by making a copy of the data before:
Fatal Exception: java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at java.util.Collections$UnmodifiableList.get(Collections.java:1050)
at xxx.core.recyclerview.delegates.ListDelegateAdapter.getItemAt(ListDelegateAdapter.kt:62)
at xxx.ui.video.VideoContentView$1.getSpanSize(VideoContentView.kt:54)
at androidx.recyclerview.widget.GridLayoutManager$SpanSizeLookup.getSpanIndex(GridLayoutManager.java:909)
at androidx.recyclerview.widget.GridLayoutManager$SpanSizeLookup.getCachedSpanIndex(GridLayoutManager.java:874)
at androidx.recyclerview.widget.GridLayoutManager.getSpanIndex(GridLayoutManager.java:468)
at androidx.recyclerview.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:541)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
at androidx.recyclerview.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1331)
at androidx.recyclerview.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1075)
at androidx.recyclerview.widget.GridLayoutManager.scrollVerticallyBy(GridLayoutManager.java:382)
at androidx.recyclerview.widget.RecyclerView.scrollStep(RecyclerView.java:1832)
at androidx.recyclerview.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:5067)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
at android.view.Choreographer.doCallbacks(Choreographer.java:574)
at android.view.Choreographer.doFrame(Choreographer.java:543)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5246)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:780)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:596)
at dalvik.system.NativeStart.main(NativeStart.java)
aa
Have a look at the following example:
private fun updateListContent(landscape: Boolean) { if (landscape) { videoListContent.setState(RxState.success(landscapeContent)) } else { videoListContent.setState(RxState.success(portraitContent)) } }
Looks nice, right? Nice-looking code can't be buggy? Or can it?
Yes it can!
What happens if videoListContent changes? In this case the changes would not be reported back to the RecyclerView...in this case we could fix it, by making a copy of the data before:
private fun updateListContent(landscape: Boolean) { if (landscape) { videoListContent.setState(RxState.success(ArrayList(landscapeContent))) } else { videoListContent.setState(RxState.success(ArrayList(portraitContent))) } }
Fatal Exception: java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at java.util.Collections$UnmodifiableList.get(Collections.java:1050)
at xxx.core.recyclerview.delegates.ListDelegateAdapter.getItemAt(ListDelegateAdapter.kt:62)
at xxx.ui.video.VideoContentView$1.getSpanSize(VideoContentView.kt:54)
at androidx.recyclerview.widget.GridLayoutManager$SpanSizeLookup.getSpanIndex(GridLayoutManager.java:909)
at androidx.recyclerview.widget.GridLayoutManager$SpanSizeLookup.getCachedSpanIndex(GridLayoutManager.java:874)
at androidx.recyclerview.widget.GridLayoutManager.getSpanIndex(GridLayoutManager.java:468)
at androidx.recyclerview.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:541)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
at androidx.recyclerview.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1331)
at androidx.recyclerview.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1075)
at androidx.recyclerview.widget.GridLayoutManager.scrollVerticallyBy(GridLayoutManager.java:382)
at androidx.recyclerview.widget.RecyclerView.scrollStep(RecyclerView.java:1832)
at androidx.recyclerview.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:5067)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
at android.view.Choreographer.doCallbacks(Choreographer.java:574)
at android.view.Choreographer.doFrame(Choreographer.java:543)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5246)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:780)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:596)
at dalvik.system.NativeStart.main(NativeStart.java)
aa