Вот основной жизненный цикл моего приложения. На данный момент он нацелен на SDK версии 8, так как я все еще использую Android 2.3.3 на своем устройстве.
- Приложение запускается, вызывается
onResume()
Вызывается методshow()
для отображения кэшированных данных. - Запускается фоновая служба, которая загружает и сохраняет данные. Он использует
AsyncTask
экземпляров для выполнения своей работы. - Одна из задач сохраняет загруженные данные в базу данных SQLite.
- Широковещательное намерение отправляется в
onPostExecute()
, когда задача сохранения завершена. MapActivity
получает намерение и обрабатывает его.
Методshow()
вызывается для отображения кэшированных и новых данных.
В методе show()
представление карты становится недействительным после добавления наложения. Это прекрасно работает, когда show()
вызывается из самой MapActivity. Однако он возбуждает исключение, когда асинхронная задача является источником вызова метода (косвенно).
Насколько я понимаю, я нахожусь в потоке пользовательского интерфейса, когда запускаю show()
в обоих случаях. Это правда?
public class CustomMapActivity extends MapChangeActivity {
private boolean showIsActive = false;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(IntentActions.FINISHED_STORING)) {
onFinishedStoring(intent);
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerReceiver(mReceiver, new IntentFilter(IntentActions.FINISHED_STORING));
}
@Override
protected void onResume() {
super.onResume();
show();
}
@Override
protected void onMapZoomPan() {
loadData();
show();
}
@Override
protected void onMapPan() {
loadData();
show();
}
@Override
protected void onMapZoom() {
loadData();
show();
}
private void onFinishedStoring(Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
boolean success = extras.getBoolean(BundleKeys.STORING_STATE);
if (success) {
show();
}
}
private void loadData() {
// Downloads data in a AsyncTask
// Stores data in AsyncTask
}
private void show() {
if (showIsActive) {
return;
}
showIsActive = true;
Uri uri = UriHelper.getUri();
if (uri == null) {
showIsActive = false;
return;
}
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
List<Overlay> mapOverlays = mapView.getOverlays();
CustomItemizedOverlay overlay = ItemizedOverlayFactory.getCustomizedOverlay(this, cursor);
if (overlay != null) {
mapOverlays.clear();
mapOverlays.add(overlay);
}
}
cursor.close();
mapView.invalidate(); // throws CalledFromWrongThreadException
showIsActive = false;
}
}
Вот трассировка стека...
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRoot.checkThread(ViewRoot.java:3020)
at android.view.ViewRoot.invalidateChild(ViewRoot.java:647)
at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:673)
at android.view.ViewGroup.invalidateChild(ViewGroup.java:2511)
at android.view.View.invalidate(View.java:5332)
at info.metadude.trees.activities.CustomMapActivity.showTrees(CustomMapActivity.java:278)
at info.metadude.trees.activities.CustomMapActivity.onMapPan(CustomMapActivity.java:126)
at info.metadude.trees.activities.MapChangeActivity$MapViewChangeListener.onChange(MapChangeActivity.java:50)
at com.bricolsoftconsulting.mapchange.MyMapView$1.run(MyMapView.java:131)
at java.util.Timer$TimerImpl.run(Timer.java:284)
Примечание. Я использую проект MapChange, чтобы получать уведомления о событиях на карте.
ИЗМЕНИТЬ:
Из того, что я сейчас прочитал в документации об AsyncTask ( прокрутите немного вниз), я не уверен, что использую его правильно. Как упоминалось ранее, я запускаю экземпляры AsyncTask
из класса Service
. Напротив, в документации говорится ...
AsyncTask позволяет выполнять асинхронную работу в пользовательском интерфейсе. Он выполняет блокирующие операции в рабочем потоке, а затем публикует результаты в потоке пользовательского интерфейса, не требуя от вас самостоятельной обработки потоков и/или обработчиков.
... что звучит так, как будто AsyncTask
следует использовать только в Activity
, а не в Service
?!
onReceive()
вызывается в основном потоке, но этот 1% зависит от того, как он был зарегистрирован. Можете ли вы показать разделregisterReceiver()
кода? - person devunwired   schedule 13.07.2012onCreate()
, чтобы показатьregisterReceiver()
. - person JJD   schedule 13.07.2012BroadcastReceiver
. Ваш код выполняется изTimer
, который выполняет задачи в различных потоках из этой библиотеки. Эта библиотека вызывает слушателя непосредственно из фонового потока, а не отправляет обратные вызовы в основной поток, как это делает платформа Android. - person devunwired   schedule 14.07.2012