Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

adding multiple event listeners
Started by tap32 Oct 31 2019 03:20 AM

9 replies to this topic
[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

tap32

[GLOBAL: userInfoPane.html]
tap32
  • Contributor

  • 252 posts
  • Corona SDK

I'm curious as to how many people can answer this without running the code. What will the following print when the user taps the rect?

local button = display.newRect(
	display.contentCenterX,
	display.contentCenterY,
	200,
	200)

for i = 1, 100 do
	local closure_i = i
	button:addEventListener("tap", function()
		print ("I am tap listener " .. closure_i)
	end)
end

I'm also curious as to what people think should actually happen. I am torn between liking and being frustrated with what actually happens. Given the documentation does not go into detail, is this intended behaviour?

 

For bonus points will the following behave differently?


local button = display.newRect(
	display.contentCenterX,
	display.contentCenterY,
	200,
	200)

local count = 0
local tapListener = function()
	count = count + 1
	print ("I am static tap listener and have been called " .. count .. " times")
end

for i = 1, 100 do
	button:addEventListener("tap", tapListener)
end



[TOPIC: post.html]
#2

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Contributor

  • 981 posts
  • Corona SDK

What a strange way to ask for help. :D

If you add 100 tap event listeners to your button, in both cases, then I would expect the respective functions to be called 100 times. With the first, you'll get numbers from 1 to 100 every time, but with the latter the numbers keep on growing because of count.

 

The only real difference that I can think of is that with the former you have a declared function that you are referencing to, which means that you can remove an event listener that calls it, whereas when you create the function within the addEventListener method, you don't have an easy reference to it and the easiest way to get rid of the listeners is to remove the button itself.

 

There is nothing to stop you from adding multiple event listeners to a single object, this is intended. Now, the extra credit question with sugar on top is why would you want to add a hundred tap listeners to a single display object?



[TOPIC: post.html]
#3

tap32

[GLOBAL: userInfoPane.html]
tap32
  • Contributor

  • 252 posts
  • Corona SDK


This is intended. Now, the extra credit question with sugar on top is why would you want to add a hundred tap listeners to a single display object?

 

That's great to hear that it's intended. It'd be nice if the docs made it clear. I think that Corona should throw an error in the second case, as I can't see a good reason why in normal use you would ever want to do it. It must always be a mistake. In the first case you might want to add or remove listeners which extend behaviour - though I think that that approach is tricky as Corona does not let you query or explicitly control the execution order of the event handlers.

 

I came across this issue with the following code:


  local listener
  listener = function()
    buttonImg:removeEventListener("tap", listener)
    func()
  end
  buttonImg:addEventListener("tap", listener)

  function buttonObject.reset()
    buttonImg:addEventListener("tap", listener)
  end

The bug occurred when I reset the button before the user had tapped it. In the end I fixed it by adding a boolean check, but it would have been quicker if Corona errored or printed a warning when the same listener was added again.

 

 



[TOPIC: post.html]
#4

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Contributor

  • 981 posts
  • Corona SDK

So, the problem isn't with the listeners, but with how you've written the functions. This is really the same thing as with your other post about setFocus.

 

Think about it like this. In order for Corona to block such behaviour automatically or to let you know when you are making any kind of mistake, it would require for these function/method calls to be rewritten with a varying number of extra checks which in turn means that it would take longer for them to run.

 

So, most (if not all) programs would become slower to run even if 99% of developers wouldn't require these extra precautions and even if they would only be helpful during production. Furthermore, there may be developers who do require multiple touch/tap event listeners to fire in their projects and if Corona were to block this for all developers, then they'd need to implement some workarounds.



[TOPIC: post.html]
#5

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 619 posts
  • Corona SDK

@tap32 I don't think Corona needs to throw and error for those events as they essentially only did what you told them to.  Unlike people, if you tell function to walk off a cliff, it will!  :)

 

As for managing listeners, I find it easier to only use "touch" listeners and then fine tune their behaviors.  The "began" phase is essentially a tap and you can add a timer to measure the length of the tap if you need to know the length of the touch.


  • pixec likes this

[TOPIC: post.html]
#6

tap32

[GLOBAL: userInfoPane.html]
tap32
  • Contributor

  • 252 posts
  • Corona SDK

So, the problem isn't with the listeners, but with how you've written the functions. This is really the same thing as with your other post about setFocus.

 

Think about it like this. In order for Corona to block such behaviour automatically or to let you know when you are making any kind of mistake, it would require for these function/method calls to be rewritten with a varying number of extra checks which in turn means that it would take longer for them to run.

 

So, most (if not all) programs would become slower to run even if 99% of developers wouldn't require these extra precautions and even if they would only be helpful during production. Furthermore, there may be developers who do require multiple touch/tap event listeners to fire in their projects and if Corona were to block this for all developers, then they'd need to implement some workarounds.

 

Thanks, I see your point, but I think that the performance issue is a red herring. Most apps will probably not be creating event listeners very often, so even with expensive checks I don't think it would be an issue. You could also just run them in the simulator.

 

 

 

@tap32 I don't think Corona needs to throw and error for those events as they essentially only did what you told them to.  Unlike people, if you tell function to walk off a cliff, it will!

 

Oh, I totally agree. However I think that it's also acceptable for an API to codify its assumptions. In other languages you might raise an exception for instance. If event listeners supported some sort of interrogation, I could even write code myself which would guard against the above.

 

Imagine the following:

function buttonObject.reset()
  if buttomImg:hasEventListener("tap", listener) then
    return
  end

  buttomImg:addEventListener("tap", listener)
end


[TOPIC: post.html]
#7

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 619 posts
  • Corona SDK

That would be cool.  Corona is open source so if you have the time, inclination and skill set, you could add that to the SDK.  There is someone in community working on Linux builds - it was a priority for him more than the community as a whole but it adds to the whole Corona ecosystem which is good for us all?



[TOPIC: post.html]
#8

tap32

[GLOBAL: userInfoPane.html]
tap32
  • Contributor

  • 252 posts
  • Corona SDK

Hmmm... after digging in the C++ code for a bit, it actually looks straightforward. It's actually in this Lua file, which the C++ code seems to invoke. I can't quite make sense of the control flow though: when running Corona is it calling into the C++, which is then calling the Lua code?

 

It could just be a case of modifying the below:

https://github.com/coronalabs/corona/blob/ccad6fd867f1745589e5b1a8e6fb3cf28a7e1a09/platform/resources/init.lua

 

Look at line 125



[TOPIC: post.html]
#9

tap32

[GLOBAL: userInfoPane.html]
tap32
  • Contributor

  • 252 posts
  • Corona SDK

So looking at that code, you can see the issue, which causes the above: there is just an array of event listeners. If it was changed to a table, we could probably remove and check for event listeners faster, but you could only have one listener for each key (or you could have an array per key).

 

 

 

I don't know though whether adding a function there would require a matching function in the C++ class.



[TOPIC: post.html]
#10

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Contributor

  • 981 posts
  • Corona SDK

Absolutely, the performance impact would be negligible, but I am still not a fan of adding overhead and complexity to code in places where it isn't necessary, no matter how insignificant.


  • pixec likes this


[topic_controls]
[/topic_controls]