正如我在上一篇文章中提到的那样,我最近在Android应用中编写了一些代码,以在服务处理带有链接的推文时通知BroadcastReceiver ,但在实现此功能时,每次发生时我都设法冻结了UI。
我犯了一个愚蠢的错误(事后看来),因为我意识到我不应该在BroadcastReceiver.onReceive中做很多逻辑,因为那部分代码是在UI线程上执行的。
引发广播消息的服务代码与上一篇文章相同:
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
}
}
然后由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);
}
}
}
}
}
特别是'resolveUrl'行可能是引起此问题的那一行,因为它进行网络调用以解析来自链接缩短器的URL 。
要停止屏幕冻结,我只需要将大多数代码从BroadcastReceiver移到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
}
}
然后,BroadcastReceiver的代码变得更加简单,这意味着我们在UI线程上的工作量减少了:
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);
}
}
}
UI的冻结消失了!
参考资料: 学习Android:使用Mark Needham博客的JCG合作伙伴Markh Needham 的BroadcastReceiver冻结UI 。
翻译自: https://www.javacodegeeks.com/2012/01/learning-android-freezing-ui-with.html