One of the key elements in my opinion is to spread out the code so it's not all in one place. If you have a function called LicenseChecker.checkLicense() which retrieves the license and checks it, you can be sure it will be disabled promptly.
The one advantage you have is that the crackers cannot see the comments of your code (and, if you obfuscate, method/variable names), so come up with something weird. In the onCreate() of one activity, you get the license ID. In onResume(), you get another value to check it against. Maybe create a thread and do some checks there. And then, some other irrelevant piece of code (maybe the player control) might pick up the value and compare it and store the result somewhere. Then three other irrelevant pieces of code will all independently check that value and disable your application if it doesn't match.
Now I should say upfront that this can cause headache for yourself - obviously, cluttered, nasty code is harder to debug and prone to cause errors. Worst case, you create false positives in legitimately purchased applications.
And, of course, everything can be reverse-engineered - once the crackers find the place where the app is disabled, they trace back the value that's being read from. They could then trace back where it's being stored, and trace that back..... or, much easier, they can just disable the final check (which is why I recommended 3 different places, all triggering delayed). Security is only as good as the weakest link.
You will not be able to stop piracy. Your best bet is to delay the spreading of a pirated copy until the initial hype about your app has calmed down.