You have two options and most likely they can be combined:
You may have a cron job that runs every X-minutes, and runs through the database, looking at each user, and checks to see if they deserve a new icon.
For example, StackOverflow implements this for the Nice Answer icon. Each time it starts, it checks how many answers there are with +10 upvotes, and sees if you need to get another badge. (He sees 5 messages with 10 upvotes and 4 wonderful response icons, you get an icon). Jeff has already stated that this means that if you receive a response that will receive 10 votes, then it will be canceled, and then another post will receive 10 votes, you will not receive the badge.
The second option is event-based triggers. Which is really simple:
$badgeSystem->giveBadge("Some Badge Name", $User_ID);
This can be used for events that you know are happening. Like an autobiographer icon. Most likely, the user will not fill out his profile if the submit button is not pressed, so the site can simply check if the user has filled everything, and if they are, and they still need an icon, they get it.
The cron task should be used for constantly monitored activities. Things like quantitative goals, such as visiting the site for 150 days or editing 500 times.
An event-based trigger should occur when an event occurs only if the user performs a specific action, such as submitting a form.
(You can probably use either almost any situation. An event-based trigger gives faster feedback, though ..)
Tyler carter
source share