BaseGameActivity.runOnUpdateThread() vs. Entity.registerUpdateHandler()

283 views Asked by At

Is there any difference if I execute a Runnable with runOnUpdateThread() or I register an update handler into an Entity and execute the code with that?

I would like to remove a Sprite from the Scene with Sprite.detachSelf(). In this case the tutorial says that this method must be invoked in the Update Thread with BaseGameActivity.runOnUpdateThread(). But with this solution I have to pass the activity object to every object that want to use the runOnUpdateThread(). Well... I do not like it.

My question is if I create a RunnableHandler object in an Entity and register it with registerUpdateHandler() and new Runnable is added to RunnableHandler, is this solution identical with the runOnUpdateThread() functionality. Is this Runnable executed in Update Thread?

/* MySprite is attached to a Scene object */
public class MySprite extends Sprite {
   private final RunnableHandler UPDATE_HANDLER = new RunnableHandler();

   public MySprite() {
       registerUpdateHandler(UPDATE_HANDLER);
   }

   /* called when the sprite has to be removed from scene */
   public void removeMyself() {
       Runnable r = new Runnable() {
           public void run() {
               detachSelf();
           }
       };
       UPDATE_HANDLER.postRunnable(r);
   }
}

I am asking this because with the standard solution everything is working fine. But with the update handler solution I got this exception:

FATAL EXCEPTION: UpdateThread java.lang.IndexOutOfBoundsException: Invalid index 19, size is 19 at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255) at java.util.ArrayList.get(ArrayList.java:308) at org.andengine.entity.Entity.onManagedUpdate(Entity.java:1402) at org.andengine.entity.scene.Scene.onManagedUpdate(Scene.java:284) at org.andengine.entity.Entity.onUpdate(Entity.java:1167) at org.andengine.engine.Engine.onUpdateScene(Engine.java:591) at org.andengine.engine.Engine.onUpdate(Engine.java:586) at org.andengine.engine.Engine.onTickUpdate(Engine.java:548) at org.andengine.engine.Engine$UpdateThread.run(Engine.java:820)

It usually comes when attach/detach functions called not in Update Thread. Am I right? Thank you in advance for your help.

1

There are 1 answers

0
Daniel Backman On

Looking at the source code in Entity a theory what happens is:

  1. The line shown, picks up a entity count = 19 (from log)
  2. one of the the entity.get(i).onUpdate() calls removeMyself()
  3. The runnable for detachSelf is queued.
  4. On the next entity.get(i).onUpdate() will result in the UpdateHandler to be run via onUpdate (updatehandlers are run in onManagedUpdate)
  5. the detachSelf removes the child from the parent list (the caller) (where entry count still 19 but the length of mChildren/entities is now 18)

Just a theory from looking at code... I think a good point to start to get the answer is to look at the loop in Entity and see if 'entities' is modified during the loop. (Note: the 'final entities' just prevents reassigning variable, not modifying the list)