mmoamenn / LuckyWheel_Android

A custom component that displays a lucky wheel. it ⁠ features easy customize of colors, addition of items and it's very trivial to integrate in your application.
MIT License
127 stars 55 forks source link

LuckyWheel crashes when it has no WheelItems to draw #23

Open mikeblas opened 3 years ago

mikeblas commented 3 years ago

Steps to reproduce:

  1. In Android Studio, create a new "Empty Activity" project
  2. Per the LuckyWheel README.md, add the dependencies to the Gradle scripts
  3. Open the activity_main.xml layout resource and add this XML block:
<com.bluehomestudio.luckywheel.LuckyWheel
        android:id="@+id/lwv"
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:layout_centerInParent="true" />
  1. With no other changes, build and run the application.

BUG: The application starts, then immediately crashes with this call stack:

D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.wheeltest1, PID: 20695
    java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
        at com.bluehomestudio.luckywheel.WheelView.onDraw(WheelView.java:240)
        at android.view.View.draw(View.java:19123)
        at android.view.View.updateDisplayListIfDirty(View.java:18073)
        at android.view.View.draw(View.java:18851)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
        at android.view.View.updateDisplayListIfDirty(View.java:18064)
        at android.view.View.draw(View.java:18851)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
        at android.view.View.updateDisplayListIfDirty(View.java:18064)
        at android.view.View.draw(View.java:18851)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
        at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1975)
        at android.view.View.updateDisplayListIfDirty(View.java:18064)
        at android.view.View.draw(View.java:18851)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
        at android.view.View.updateDisplayListIfDirty(View.java:18064)
        at android.view.View.draw(View.java:18851)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
        at android.view.View.updateDisplayListIfDirty(View.java:18064)
        at android.view.View.draw(View.java:18851)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
        at android.view.View.updateDisplayListIfDirty(View.java:18064)
        at android.view.View.draw(View.java:18851)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
        at android.view.View.updateDisplayListIfDirty(View.java:18064)
        at android.view.View.draw(View.java:18851)
        at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
        at android.view.View.draw(View.java:19126)
        at com.android.internal.policy.DecorView.draw(DecorView.java:785)
        at android.view.View.updateDisplayListIfDirty(View.java:18073)
        at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:643)
        at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:649)
        at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:757)
        at android.view.ViewRootImpl.draw(ViewRootImpl.java:2980)
        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2794)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2347)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1386)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6733)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
        at android.view.Choreographer.doCallbacks(Choreographer.java:723)
        at android.view.Choreographer.doFrame(Choreographer.java:658)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

The problem is that the LuckyWheel doesn't check to see if the list of WheelItems is empty. While that's not a great use case, sometimes in development not all steps are completed. The control would offer developers a better experience if it was able to draw itself without crashing when it contained no WheelItems. Perhaps just a circle would be fine -- and maybe log a warning that there were no items in the control to be drawn.

mmoamenn commented 2 years ago

PR in review