0
\$\begingroup\$

I am using Canvas in my android game. When I remove a no longer displayed entity in my entity list, all other entities are flickering for a brief time. When it's not removed, there is no such problem. But since I am not a big fan of memory leaks, that's not an option.

The canvas rendering system is already double-buffered by design and I have utterly no idea how to fix such a problem. I have thought maybe it is because the list is sorting itself after the item removal and tried changing it to a Set, but that didn't work either.

Does anyone have any idea why this might be happening and how to fix it?

Structure of the code:

private val gameObjects: List<GameObject> = mutableListOf()
    
    fun update(deltaTime: Long)
    {
        gameObjects.forEach {
            it.update(deltaTime)
    }

 fun render(canvas: Canvas)
    {
      gameObjects.forEach {
         when (getVisibilityStatus(it.virtualY))
         {
            VisibilityStatus.VISIBLE -> it.render(canvas, virtualToPhysicalY(it.virtualY))

            VisibilityStatus.BELOW_SCREEN ->
            {
              if (virtualToPhysicalY(it.virtualY) > screenSizePairXY.second)
                gameObjects.remove(it)
            
            }
         }
    }
\$\endgroup\$
1
\$\begingroup\$

Apparently removing an item from a list that you are iterating isn't such a good idea. Separating the cleanup/removal process from the render for each loop fixed the issue.

      private val gameObjects: List<GameObject> = mutableListOf()
      private val gameObjectsToRemove: List<GameObject> = mutableListOf()

    
   /**
    * Removes the invisible objects (if any) to save memory
    */
      private fun cleanUp()
        {
            gameObjectsToRemove.forEach {
                gameObjects.remove(it)
            }
            gameObjectsToRemove.clear()
        }
        
        fun update(deltaTime: Long)
        {
            cleanUp()
            gameObjects.forEach {
                it.update(deltaTime)
        }
    
     fun render(canvas: Canvas)
        {
          gameObjects.forEach {
             when (getVisibilityStatus(it.virtualY))
             {
                VisibilityStatus.VISIBLE -> it.render(canvas, virtualToPhysicalY(it.virtualY))
    
                VisibilityStatus.BELOW_SCREEN ->
                {
                  if (virtualToPhysicalY(it.virtualY) > screenSizePairXY.second)
                    gameObjectsToRemove.add(it)
                
                }
             }
    }
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ You might want to use removeAll instead of calling remove in a loop. \$\endgroup\$ – DMGregory Sep 1 at 13:13
  • \$\begingroup\$ Yeah sure why not, thanks \$\endgroup\$ – DeveloperKurt Sep 1 at 14:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.