App freezes on button press!

Hello everyone,

I got a tough problem in my current project.

I’ve got a button class with a “touch” function relativly similar to the ones in the Button Widget.

From time to time, when I hit this button, the app freezes. It does so in the simulator and on a device, without any error message. This happens in a completly unpredictable manner and I’ve got no idea how to tackle this issue.

Below is the code of the buttons touch function:

function RoundButton:touch(event) local phase = event.phase local event\_x, event\_y = event.x, event.y local event\_target = event.target local target\_x, target\_y = event\_target.x, event\_target.y if phase == "began" and not self.isFocus then display.getCurrentStage():setFocus(event\_target) self.isFocus = true self.isPressed = true if self.callback then self.callback({phase = "began", target = self}) end elseif self.isFocus then if phase == "moved" and self.isPressed then local target\_world\_x, target\_world\_y = event\_target:localToContent(0,0) local dis\_x, dis\_y = math\_abs(target\_world\_x-event\_x), math\_abs(target\_world\_y-event\_y) if dis\_x\*2-10 \> event\_target.width or dis\_y\*2-10 \> event\_target.height then self.isPressed = nil if self.callback then self.callback({phase = "cancelled", target = self}) end end else display.getCurrentStage():setFocus(nil) self.isFocus = nil if self.isPressed then if self.callback then self.callback({phase = "ended", target = self}) end end self.isPressed = nil end end return true end

The only problem I could think of is, that I remove the buttons touch listener in some of the callback functions. Could that cause the problem?

Unfortunetly I’m not really able to test, because the bug only occurs in around 1% of the cases.

Would be great if someone has an idea.

Greetings

Torben Ratzlaff

Does nobody has an idea?

Especially the Corona staff, cause unhandled App crashes are one of the biggest problems, as they can’t be debugged that easy.

Its going to be hard to look at that code and find a problem.  We don’t see how the buttons are created, the object that it’s a part of, or how you’re using and removing them.

We want to try and get rid of those type of crashes, but if its hard to reproduce it, it’s going to be hard for us to find it.

Rob

Hi Rob,
thanks for your reply.
I would be glad to provide you with all the required information you need, but it sounds
like that wouldn’t help you much. Anyways, here is the whole button class that I use.
 

local empty\_table = {} local math\_abs = math.abs local easing\_inOutSine = easing.inOutSine local RoundButton = {} RoundButton.metatable = {\_\_index = RoundButton} RoundButton.class = "RoundButton" function RoundButton:new(arg) local instance = {} setmetatable(instance, RoundButton.metatable) local arg = arg or empty\_table instance.callback = arg.callback return instance end function RoundButton:delete() self:erase() end function RoundButton:draw(layer) local graphic\_obj = self.graphic\_obj if not graphic\_obj then self.isFocus = nil self.isPressed = nil graphic\_obj = display.newGroup() graphic\_obj.x, graphic\_obj.y = x, y self.graphic\_obj = graphic\_obj local graphic\_container = display.newGroup() self.graphic\_container = graphic\_container local stone\_shadow = display.newImage("images/btn\_shadow\_01.png") stone\_shadow.x, stone\_shadow.y = 5, 15 stone\_shadow.alpha = 0.7 stone\_shadow.blendMode = "multiply" local stone\_bg = display.newImage("images/round\_btn\_01.png") self.stone\_bg = stone\_bg local button = display.newRect(0,0,140,140) button.alpha = 0.5 button.x, button.y = 1, 3 button.isVisible = false button.isHitTestable = true self.button = button graphic\_container:insert(stone\_shadow) graphic\_container:insert(stone\_bg) graphic\_obj:insert(graphic\_container) graphic\_obj:insert(button) end graphic\_obj.isVisible = false if layer then layer:insert(graphic\_obj) end end function RoundButton:erase() local graphic\_obj = self.graphic\_obj if graphic\_obj then display.remove(graphic\_obj) self.graphic\_obj = nil self.graphic\_container = nil self.stone\_bg = nil self.button = nil self.isFocus = nil self.isPressed = nil self.has\_listener = nil end end function RoundButton:show(arg) local graphic\_obj = self.graphic\_obj local graphic\_container = self.graphic\_container if graphic\_obj then local arg = arg or empty\_table local x, y = arg.x or graphic\_obj.x, arg.y or graphic\_obj.y local layer = arg.layer self.callback = arg.callback or self.callback self.isFocus = nil self.isPressed = nil graphic\_obj.isVisible = true graphic\_obj.x, graphic\_obj.y = x, y graphic\_container.xScale, graphic\_container.yScale = 1, 1 if layer then layer:insert(graphic\_obj) end end end function RoundButton:hide() local graphic\_obj = self.graphic\_obj if graphic\_obj then graphic\_obj.isVisible = false self.isFocus = nil self.isPressed = nil end end function RoundButton:start() local graphic\_obj = self.graphic\_obj local button = self.button local graphic\_container = self.graphic\_container if graphic\_obj and not self.isActive then self.isActive = true if not self.has\_listener then self.has\_listener = true button:addEventListener("touch", self) end end end function RoundButton:pause() local graphic\_obj = self.graphic\_obj local button = self.button if graphic\_obj and self.isActive then self.isActive = false end end function RoundButton:getGroup() return self.graphic\_obj end function RoundButton:insert(object) local graphic\_obj = self.graphic\_obj local graphic\_container = self.graphic\_container if graphic\_obj and object then graphic\_container:insert(object) end end function RoundButton:touch(event) if self.isActive then local phase = event.phase local event\_x, event\_y = event.x, event.y local event\_target = event.target local target\_x, target\_y = event\_target.x, event\_target.y local graphic\_container = self.graphic\_container if phase == "began" and not self.isFocus then display.getCurrentStage():setFocus(event\_target) self.isFocus = true self.isPressed = true graphic\_container.xScale, graphic\_container.yScale = 0.9, 0.9 if self.callback then self.callback({phase = "began", target = self}) end elseif self.isFocus then if phase == "moved" and self.isPressed then local target\_world\_x, target\_world\_y = event\_target:localToContent(0,0) local dis\_x, dis\_y = math\_abs(target\_world\_x-event\_x), math\_abs(target\_world\_y-event\_y) if dis\_x\*2-10 \> event\_target.width or dis\_y\*2-10 \> event\_target.height then self.isPressed = nil graphic\_container.xScale, graphic\_container.yScale = 1, 1 if self.callback then self.callback({phase = "cancelled", target = self}) end end else display.getCurrentStage():setFocus(nil) self.isFocus = nil graphic\_container.xScale, graphic\_container.yScale = 1, 1 if self.isPressed then if self.callback then self.callback({phase = "ended", target = self}) end end self.isPressed = nil end end return true else return false end end function RoundButton:clearFocus() local graphic\_obj = self.graphic\_obj local graphic\_container = self.graphic\_container if graphic\_obj then display.getCurrentStage():setFocus(nil) self.isFocus = nil self.isPressed = nil graphic\_container.xScale, graphic\_container.yScale = 1, 1 end end return RoundButton

I don’t see anything obvious.

Rob

Try this ::

function RoundButton:touch(event) if self.isActive then local phase = event.phase local event\_x, event\_y = event.x, event.y local event\_target = event.target local target\_x, target\_y = event\_target.x, event\_target.y local graphic\_container = self.graphic\_container if phase == "began" and not self.isFocus then display.getCurrentStage():setFocus(event\_target) self.isFocus = true self.isPressed = true graphic\_container.xScale, graphic\_container.yScale = 0.9, 0.9 if self.callback then self.callback({phase = "began", target = self}) end elseif self.isFocus then if phase == "moved" and self.isPressed then local target\_world\_x, target\_world\_y = event\_target:localToContent(0,0) local dis\_x, dis\_y = math\_abs(target\_world\_x-event\_x), math\_abs(target\_world\_y-event\_y) if dis\_x\*2-10 \> event\_target.width or dis\_y\*2-10 \> event\_target.height then self.isPressed = nil graphic\_container.xScale, graphic\_container.yScale = 1, 1 if self.callback then self.callback({phase = "cancelled", target = self}) end end else display.getCurrentStage():setFocus(nil) self.isFocus = nil graphic\_container.xScale, graphic\_container.yScale = 1, 1 if self.isPressed then if self.callback then self.callback({phase = "ended", target = self}) end end self.isPressed = nil end end end return true end

@Rob

Thanks anyways.

@Christopher

Thanks alot, but the only difference I see is removing the “return false” at the end, which I already tried :frowning:

Yep, removed return false and moved “return true” to outside your “if” block, that seemed to have done the trick in my test.

As I said, the freez only occures in one of 100 cases in general, which is the problem.

I can only ensure that a way does not work and not that it is working fine :frowning:

Does nobody has an idea?

Especially the Corona staff, cause unhandled App crashes are one of the biggest problems, as they can’t be debugged that easy.

Its going to be hard to look at that code and find a problem.  We don’t see how the buttons are created, the object that it’s a part of, or how you’re using and removing them.

We want to try and get rid of those type of crashes, but if its hard to reproduce it, it’s going to be hard for us to find it.

Rob

Hi Rob,
thanks for your reply.
I would be glad to provide you with all the required information you need, but it sounds
like that wouldn’t help you much. Anyways, here is the whole button class that I use.
 

local empty\_table = {} local math\_abs = math.abs local easing\_inOutSine = easing.inOutSine local RoundButton = {} RoundButton.metatable = {\_\_index = RoundButton} RoundButton.class = "RoundButton" function RoundButton:new(arg) local instance = {} setmetatable(instance, RoundButton.metatable) local arg = arg or empty\_table instance.callback = arg.callback return instance end function RoundButton:delete() self:erase() end function RoundButton:draw(layer) local graphic\_obj = self.graphic\_obj if not graphic\_obj then self.isFocus = nil self.isPressed = nil graphic\_obj = display.newGroup() graphic\_obj.x, graphic\_obj.y = x, y self.graphic\_obj = graphic\_obj local graphic\_container = display.newGroup() self.graphic\_container = graphic\_container local stone\_shadow = display.newImage("images/btn\_shadow\_01.png") stone\_shadow.x, stone\_shadow.y = 5, 15 stone\_shadow.alpha = 0.7 stone\_shadow.blendMode = "multiply" local stone\_bg = display.newImage("images/round\_btn\_01.png") self.stone\_bg = stone\_bg local button = display.newRect(0,0,140,140) button.alpha = 0.5 button.x, button.y = 1, 3 button.isVisible = false button.isHitTestable = true self.button = button graphic\_container:insert(stone\_shadow) graphic\_container:insert(stone\_bg) graphic\_obj:insert(graphic\_container) graphic\_obj:insert(button) end graphic\_obj.isVisible = false if layer then layer:insert(graphic\_obj) end end function RoundButton:erase() local graphic\_obj = self.graphic\_obj if graphic\_obj then display.remove(graphic\_obj) self.graphic\_obj = nil self.graphic\_container = nil self.stone\_bg = nil self.button = nil self.isFocus = nil self.isPressed = nil self.has\_listener = nil end end function RoundButton:show(arg) local graphic\_obj = self.graphic\_obj local graphic\_container = self.graphic\_container if graphic\_obj then local arg = arg or empty\_table local x, y = arg.x or graphic\_obj.x, arg.y or graphic\_obj.y local layer = arg.layer self.callback = arg.callback or self.callback self.isFocus = nil self.isPressed = nil graphic\_obj.isVisible = true graphic\_obj.x, graphic\_obj.y = x, y graphic\_container.xScale, graphic\_container.yScale = 1, 1 if layer then layer:insert(graphic\_obj) end end end function RoundButton:hide() local graphic\_obj = self.graphic\_obj if graphic\_obj then graphic\_obj.isVisible = false self.isFocus = nil self.isPressed = nil end end function RoundButton:start() local graphic\_obj = self.graphic\_obj local button = self.button local graphic\_container = self.graphic\_container if graphic\_obj and not self.isActive then self.isActive = true if not self.has\_listener then self.has\_listener = true button:addEventListener("touch", self) end end end function RoundButton:pause() local graphic\_obj = self.graphic\_obj local button = self.button if graphic\_obj and self.isActive then self.isActive = false end end function RoundButton:getGroup() return self.graphic\_obj end function RoundButton:insert(object) local graphic\_obj = self.graphic\_obj local graphic\_container = self.graphic\_container if graphic\_obj and object then graphic\_container:insert(object) end end function RoundButton:touch(event) if self.isActive then local phase = event.phase local event\_x, event\_y = event.x, event.y local event\_target = event.target local target\_x, target\_y = event\_target.x, event\_target.y local graphic\_container = self.graphic\_container if phase == "began" and not self.isFocus then display.getCurrentStage():setFocus(event\_target) self.isFocus = true self.isPressed = true graphic\_container.xScale, graphic\_container.yScale = 0.9, 0.9 if self.callback then self.callback({phase = "began", target = self}) end elseif self.isFocus then if phase == "moved" and self.isPressed then local target\_world\_x, target\_world\_y = event\_target:localToContent(0,0) local dis\_x, dis\_y = math\_abs(target\_world\_x-event\_x), math\_abs(target\_world\_y-event\_y) if dis\_x\*2-10 \> event\_target.width or dis\_y\*2-10 \> event\_target.height then self.isPressed = nil graphic\_container.xScale, graphic\_container.yScale = 1, 1 if self.callback then self.callback({phase = "cancelled", target = self}) end end else display.getCurrentStage():setFocus(nil) self.isFocus = nil graphic\_container.xScale, graphic\_container.yScale = 1, 1 if self.isPressed then if self.callback then self.callback({phase = "ended", target = self}) end end self.isPressed = nil end end return true else return false end end function RoundButton:clearFocus() local graphic\_obj = self.graphic\_obj local graphic\_container = self.graphic\_container if graphic\_obj then display.getCurrentStage():setFocus(nil) self.isFocus = nil self.isPressed = nil graphic\_container.xScale, graphic\_container.yScale = 1, 1 end end return RoundButton

I don’t see anything obvious.

Rob

Try this ::

function RoundButton:touch(event) if self.isActive then local phase = event.phase local event\_x, event\_y = event.x, event.y local event\_target = event.target local target\_x, target\_y = event\_target.x, event\_target.y local graphic\_container = self.graphic\_container if phase == "began" and not self.isFocus then display.getCurrentStage():setFocus(event\_target) self.isFocus = true self.isPressed = true graphic\_container.xScale, graphic\_container.yScale = 0.9, 0.9 if self.callback then self.callback({phase = "began", target = self}) end elseif self.isFocus then if phase == "moved" and self.isPressed then local target\_world\_x, target\_world\_y = event\_target:localToContent(0,0) local dis\_x, dis\_y = math\_abs(target\_world\_x-event\_x), math\_abs(target\_world\_y-event\_y) if dis\_x\*2-10 \> event\_target.width or dis\_y\*2-10 \> event\_target.height then self.isPressed = nil graphic\_container.xScale, graphic\_container.yScale = 1, 1 if self.callback then self.callback({phase = "cancelled", target = self}) end end else display.getCurrentStage():setFocus(nil) self.isFocus = nil graphic\_container.xScale, graphic\_container.yScale = 1, 1 if self.isPressed then if self.callback then self.callback({phase = "ended", target = self}) end end self.isPressed = nil end end end return true end

@Rob

Thanks anyways.

@Christopher

Thanks alot, but the only difference I see is removing the “return false” at the end, which I already tried :frowning:

Yep, removed return false and moved “return true” to outside your “if” block, that seemed to have done the trick in my test.

As I said, the freez only occures in one of 100 cases in general, which is the problem.

I can only ensure that a way does not work and not that it is working fine :frowning: