1. 背景
前段时间测试反馈一个ANR问题,查看代码后发现是在BroadcastReceiver中执行了耗时的数据库初始化操作:
public static class LocaleChangeBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
LogSug.w_w("LocaleChangeReceiver", "intent is null");
return;
}
if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
LogSug.i_i("LocaleChangeReceiver", "Language change");
if (dbFactory != null) {
dbFactory.initDB();
}
}
}
}
首先解释一下为什么要在BroadcastReceiver中初始化数据库。因为我们的数据库是不支持多语言的,就是说里面存储的数据要不都是中文,要不都是英文或者其他语言,总之不能又有中文又有英文,所以每次系统语言切换的时候,数据库也要重新初始化。所以这个BroadcastReceiver是用来监听系统切换语言的广播:Intent.ACTION_LOCALE_CHANGED
,监听到以后就会执行数据库初始化操作。
BroadcastReceiver的ANR时限是10秒,也就是输如果onReceive()
超过十秒还没执行完,系统就会报ANR。为了避免这种情况,第一时间想到两个方案:
- 创建啊子线程去执行耗时操作
- 在BroadcastReceiver中拉起Service,把耗时操作放到Service中去执行
2. 在BroadcastReceiver中起子线程
在BroadcastReceiver中起子线程执行耗时操作不是一个可靠的方法,具体原因网上有很多介绍,这里就不赘述了。可以参考这篇博客:
为什么不能在BroadcastReceiver中开启子线程
3. 用Intent拉起Service执行耗时操作
现在来看第二种方法,当BroadcastReceiver收到广播后,在onReceive()
中拉起一个Service,这样就解决了ANR的问题,也不用担心onReceive执行完后被系统杀掉。代码如下:
public static class LocaleChangeBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
LogSug.w_w(