Обновление Активности от BroadcastReceiver
Этот вопрос поднял интересную проблему.
У OP есть приложение, которое отображает карту, и эта карта должна быть обновлена с помощью маркеров местоположения, полученных с помощью SMS-сообщений. Отдельные шаги довольно просты: SMS-сообщения могут быть получены BroadcastReceiver
маркеры могут отображаться ItemizedOverlay
на вершине MapView
, Сложнее всего, чтобы принимающая часть связывалась с основной частью приложения.
Что произойдет, если приложение имеет активный
MapActivity
, а затем егоBroadcastReceiver
вызывается как ответ на входящее СМС? ЭтоMapActivity
приостановлено в то время какBroadcastReceiver
код выполняется в том же процессе? Если это так, это безопасно дляBroadcastReceiver
чтобы получить доступ кMapActivity
через статическую ссылку (которая устанавливаетсяonCreate
метод?И наоборот, это приложение
BroadcastReceiver
выполняется в отдельном процессе, и, следовательно, потребуется ли какой-то другой способ связи с активностью приложения?
3 ответа
Читая документы, похоже, что BroadcastReceiver выполняется в другом процессе, хотя я не уверен на 100% ( жизненный цикл BroadcastReceiver)
Процесс, который в данный момент выполняет BroadcastReceiver (то есть в настоящее время выполняет код в своем методе onReceive(Context, Intent)), считается процессом переднего плана.
При этом я не считаю безопасным доступ к активности из onReceive, так как это другой процесс, и он, вероятно, завершится сбоем.
Примите во внимание, что Activity также может действовать как BroadcastReceiver, то есть вы должны контролировать, когда в своем жизненном цикле он активно прослушивает события. Таким образом, вы можете подписаться в onResume (код, извлеченный из проекта ZXing)
public void onResume(){
activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
[...]
}
public void onPause() {
[...]
activity.unregisterReceiver(powerStatusReceiver);
}
И вы определяете BroadcastReceiver как закрытый класс внутри публичного класса
final class InactivityTimer {
[onResume, onPause, rest of the stuff ...]
private final class PowerStatusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
// 0 indicates that we're on battery
// In Android 2.0+, use BatteryManager.EXTRA_PLUGGED
int batteryPlugged = intent.getIntExtra("plugged", -1);
if (batteryPlugged > 0) {
InactivityTimer.this.cancel();
}
}
}
}
}
Таким образом, BroadcastReceiver всегда должен сохранять новые маркеры (через Сервис, никогда не внутри onReceive) И он должен уведомлять потенциально активную MapActivity о добавлении новых маркеров, которые будут прослушивать, если он активен.
Или, что еще проще, Activity и BroadcastReceiver прослушивают одно и то же SMS-намерение. В то время как последний сохраняет это, первый обновляет карту, но я просто догадываюсь, что я попробую.
BroadcastReceiver
должен работать в том же процессе. BroadcastReceiver
разработан, чтобы быть недолгим. Как таковой он может выполняться без какого-либо реального беспокойства о приостановке переднего плана Activity
, Вы можете получить доступ к Activity
непосредственно через статическую ссылку, если вы проверили случай, когда Activity
еще не был создан. Тем не менее, это может иметь больше смысла для общения через интенты.
Наилучший подход, как отмечали другие, заключается в создании отдельного намерения, которое является частным для приложения. Вместо того, чтобы объявлять его в манифесте, действие регистрирует его всякий раз, когда оно активно. Этот ответ объясняет, как к этому.
Публика BroadcastReceiver
(который объявлен в манифесте и обрабатывает android.provider.Telephony.SMS_RECEIVED
) должен затем вызвать это специфическое для приложения намерение.