Learning Android: Freezing the UI with a BroadcastReceiver
I made the stupid (in hindsight) mistake of not realising that I shouldn’t be doing a lot of logic in BroadcastReceiver.onReceive since that bit of code gets executed on the UI thread.
The service code which raises the broadcast message is the same as in the previous post:
public class TweetService extends IntentService { ... @Override protected void onHandleIntent(Intent intent) { StatusListener listener = new UserStreamListener() { // override a whole load of methods - removed for brevity public void onStatus(Status status) { String theTweet = status.getText(); if (status.getText().contains("http://")) { Intent tweetMessage = new Intent(TweetTask.NEW_TWEET); tweetMessage.putExtra(android.content.Intent.EXTRA_TEXT, status.getText()); sendBroadcast(tweetMessage); } } }; // code to connect to the twitter streaming API } }
That is then handled like this by the BroadcastReceiver:
public class MyActivity extends Activity { protected void onPause() { super.onPause(); if (dataUpdateReceiver != null) unregisterReceiver(dataUpdateReceiver); } protected void onResume() { super.onResume(); if (dataUpdateReceiver == null) dataUpdateReceiver = new DataUpdateReceiver(); IntentFilter intentFilter = new IntentFilter(TweetTask.NEW_TWEET); registerReceiver(dataUpdateReceiver, intentFilter); } private class DataUpdateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(TweetTask.NEW_TWEET)) { Pattern p = Pattern.compile("(http://[^\\s]+)"); String theTweet = intent.getStringExtra(TweetTask.NEW_TWEET); Matcher matcher = p.matcher(theTweet); int startIndex = -1; int endIndex = -1; while (matcher.find()) { startIndex = matcher.start(); endIndex = matcher.end(); } if (startIndex != -1 && endIndex != -1) { String resolvedUrl = resolveUrl(theTweet.substring(startIndex, endIndex)); saveToDatabase(resolvedUrl); updateUI(resolvedUrl); } } } } }
In particular the ‘resolveUrl’ line was probably the one one causing the problem since it makes a network call to resolve URLs from link shorteners.
To stop the screen freezing up I just needed to move most of the code from BroadcastReceiver into the TweetService:
public class TweetService extends IntentService { ... @Override protected void onHandleIntent(Intent intent) { StatusListener listener = new UserStreamListener() { // override a whole load of methods - removed for brevity public void onStatus(Status status) { String theTweet = status.getText(); if (status.getText().contains("http://")) { Pattern p = Pattern.compile("(http://[^\\s]+)"); Matcher matcher = p.matcher(theTweet); int startIndex = -1; int endIndex = -1; while (matcher.find()) { startIndex = matcher.start(); endIndex = matcher.end(); } if (startIndex != -1 && endIndex != -1) { String resolvedUrl = resolveUrl(theTweet.substring(startIndex, endIndex)); saveToDatabase(resolvedUrl); Intent tweetMessage = new Intent(TweetTask.NEW_TWEET); tweetMessage.putExtra(android.content.Intent.EXTRA_TEXT, resolvedUrl); sendBroadcast(tweetMessage); } } } }; // code to connect to the twitter streaming API } }
And then the code for BroadcastReceiver becomes much simpler which means we’re doing less work on the UI thread:
private class DataUpdateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(TweetTask.NEW_TWEET)) { String url = intent.getStringExtra(TweetTask.NEW_TWEET); updateUI(url); } } }
And the freezing up of the UI is gone!
Reference: Learning Android: Freezing the UI with a BroadcastReceiver from our JCG partner Markh Needham at the Mark Needham Blog.