Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash in ParticleField.onDraw #19

Closed
kibantony opened this issue Apr 23, 2015 · 3 comments
Closed

Crash in ParticleField.onDraw #19

kibantony opened this issue Apr 23, 2015 · 3 comments

Comments

@kibantony
Copy link

There is a concurrency problem that is causing constant repeatable crashes. I've traced the issue to the fact that ParticleSystem.onUpdate is called via a Timer on a non-UI thread where it changes the contents of the mActiveParticles array. Meanwhile, the ParticleField view is accessing the same array to draw the particles on the UI thread, leading to the crash. A quick fix would be synchronize on the array to alleviate the contention, or use a Handler or similar mechanism to schedule the onUpdate operation on the UI thread.

java.lang.IndexOutOfBoundsException: Invalid index 50, size is 50
        at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
        at java.util.ArrayList.get(ArrayList.java:308)
        at com.plattysoft.leonids.ParticleField.onDraw(ParticleField.java:36)
        at android.view.View.draw(View.java:14692)
        at android.view.View.getDisplayList(View.java:13573)
        at android.view.View.getDisplayList(View.java:13627)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3095)
        at android.view.View.getDisplayList(View.java:13498)
        at android.view.View.getDisplayList(View.java:13627)
        at android.view.View.draw(View.java:14409)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3121)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2947)
        at android.view.View.draw(View.java:14695)
        at android.widget.FrameLayout.draw(FrameLayout.java:472)
        at android.view.View.getDisplayList(View.java:13573)
        at android.view.View.getDisplayList(View.java:13627)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3095)
        at android.view.View.getDisplayList(View.java:13498)
        at android.view.View.getDisplayList(View.java:13627)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3095)
        at android.view.View.getDisplayList(View.java:13498)
        at android.view.View.getDisplayList(View.java:13627)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3095)
        at android.view.View.getDisplayList(View.java:13498)
        at android.view.View.getDisplayList(View.java:13627)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3095)
        at android.view.View.getDisplayList(View.java:13498)
        at android.view.View.getDisplayList(View.java:13627)
        at android.view.HardwareRenderer$GlRenderer.buildDisplayList(HardwareRenderer.java:1773)
        at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1638)
        at android.view.ViewRootImpl.draw(ViewRootImpl.java:2624)
        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2469)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2035)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1095)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6010)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:799)
        at android.view.Choreographer.doCallbacks(Choreographer.java:599)
        at android.view.Choreographer.doFrame(Choreographer.java:559)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:784)
        at android.os.Handler.handleCallback(Handler.java:733)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:157)
        at android.app.ActivityThread.main(ActivityThread.java:5872)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:852)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:668)
        at dalvik.system.NativeStart.main(Native Method)
@plattysoft
Copy link
Owner

Thanks for the heads up. Surprisingly enough I have never seen this crash myself, but by looking at the stack trace and your explanation I must have just been lucky.

How do you manage to replicate it? It may be dependant on the Android version.

@kibantony
Copy link
Author

No problem. It's a great library and really saved me some time apart from this small issue. My test device is running 4.4.2. I'm creating the ParticleSystem like so...

mParticles = new ParticleSystem((Activity)getContext(), 100, R.drawable.particle, 5000)
    .setSpeedRange(0.0f, 0.1f)
    .setScaleRange(0.1f, 0.9f)
    .setFadeOut(1000)
    .setParentViewGroup((ViewGroup) findViewById(R.id.particle_view));
mParticles.emit(0, 0, 10);

In my parent view's onSizeChanged function I do the following to ensure the particles emit from the center on the view...

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mParticles.updateEmitPoint(w / 2, h / 2);
}

I'm also running some other animations within the parent view which cause frequent invalidates. All I have to do to see the crash is sit and let it run. Sometimes it happens immediately, sometimes it takes a couple minutes. It seems to happen a bit faster if I change the orientation (landscape<>portrait) of the device a few times to cause the view to resize & invalidate.

I quickly worked around it by adding a synchronized(mActiveParticles) {} block in ParticleSystem.onUpdate, and a synchronized (mParticles) {} in ParticleField.onDraw. No more crashes.

@plattysoft
Copy link
Owner

It could be that on rotation some particles are "lost" but definitely, I'm
going to add the synchronized part.

Thanks for the heads up!

On Fri, 24 Apr 2015 6:13 pm kibantony notifications@github.com wrote:

No problem. It's a great library and really saved me some time apart from
this small issue. My test device is running 4.4.2. I'm creating the
ParticleSystem like so...

mParticles = new ParticleSystem((Activity)getContext(), 100, R.drawable.particle, 5000)
.setSpeedRange(0.0f, 0.1f)
.setScaleRange(0.1f, 0.9f)
.setFadeOut(1000)
.setParentViewGroup((ViewGroup) findViewById(R.id.particle_view));
mParticles.emit(0, 0, 10);

In my parent view's onSizeChanged function I do the following to ensure
the particles emit from the center on the view...

@OverRide
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mParticles.updateEmitPoint(w / 2, h / 2);
}

I'm also running some other animations within the parent view which cause
frequent invalidates. All I have to do to see the crash is sit and let it
run. Sometimes it happens immediately, sometimes it takes a couple minutes.
It seems to happen a bit faster if I change the orientation
(landscape<>portrait) of the device a few times to cause the view to resize
& invalidate.

I quickly worked around it by adding a synchronized(mActiveParticles) {}
block in ParticleSystem.onUpdate, and a synchronized (mParticles) {} in
ParticleField.onDraw. No more crashes.


Reply to this email directly or view it on GitHub
#19 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants