Well, main loop might be a good idea when you actually want to do all animations, object positioning and other things all by yourself, and stashing your main loop code in an update handler should work as long as you don't do some really complex and time-consuming operations there. But why do that if the engine can handle most of the stuff for you?
For example, you can have a main loop and check if the screen has been touched, and if the touched came in a valid area. If so you set a correct flag and start animating some sprites moving them from frame to frame and keep checking each frame how far you still have to move them, and update the objects graph when animation is finished.
On the other hand you can just set attach a onTouch listener to some sprite and have its callback fire precisely when it is needed - when the screen has been touched in a certain place. You'll not only know that a screen touch occurred but you'll also know if it actually hit the sprite as the callback won't fire otherwise. No need to check it yourself. When you need to take some action based on received touch, for example move some sprites around you just attach a shape modifier to them and andengine moves them where they need to go, it even can do cool stuff like accelerating, decelerating, bouncing and others (ease functions). Again, no need to do anything but passing movement parameters to the engine. Instead of updating the object graph every frame you can add listeners to shape modifiers so that their callback will be launched whenever the movement is finished and update the graph then.
I guess you should get the idea by now so i won't go on

For me using listeners and scrapping the main loop took some time to get used to, as i usually coded in C and assembler so far and relied on such loops heavily. Also you have to put some thought into it and take into account that unlike the main loop the callbacks work asynchronously and one callback can be launched while you're handling other, potentially leading to a game-crashing situation. But you can always have some flags indicating what is happening and either service or ignore launched callbacks based on them - for example in a puzzle game you wouldn't want to start a new sprite move before the previous one has finished so you'd have to ignore or buffer incoming screen tap for later use.
But in the end, after getting used to, building your game on listeners and callbacks really makes your life easier and your code more efficient, simpler and it's totally worth the effort even if you need to redesign the game.