【发布时间】:2012-07-12 21:52:46
【问题描述】:
这是我的应用程序的基本生命周期。它现在针对的是 SDK 版本 8,因为我的设备上仍在运行 Android 2.3.3。
- 应用程序启动,
onResume()被调用
调用show()方法显示缓存数据。 - 后台服务启动,下载和存储数据。它使用
AsyncTask实例来完成其工作。 - 其中一项任务将下载的数据存储在 SQLite 数据库中。
- 当存储任务完成时,会在
onPostExecute()中发送广播意图。 -
MapActivity接收意图并处理它。
调用show()方法来显示缓存和新数据。
在show() 方法中,地图视图在添加叠加层后无效。当从 MapActivity 本身调用 show() 时,这可以正常工作。但是,当异步任务是方法调用的来源(间接)时,它引发异常。
据我了解,当我在这两种情况下触发 show() 时,我都处于 UI 线程。这是真的吗?
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 项目来接收有关地图事件的通知。
编辑:
从我现在在documentation about AsyncTask 中读到的内容(向下滚动一点),我不确定我是否以正确的方式使用它。如前所述,我从Service 类中启动AsyncTask 实例。相反,文档状态...
AsyncTask 允许您在用户界面上执行异步工作。它在工作线程中执行阻塞操作,然后在 UI 线程上发布结果,无需您自己处理线程和/或处理程序。
...听起来好像AsyncTask 只能在Activity 中使用,而不是在Service@ 中使用?!
【问题讨论】:
-
您是正确的,99% 的时间
onReceive()在主线程上被调用,但 1% 取决于它是如何注册的。你能显示代码的registerReceiver()部分吗? -
@Devunwired 我添加了
onCreate()方法来显示registerReceiver()。 -
我仍然有兴趣帮助您找出发生这种情况的原因。您可以从错误的线程异常中发布堆栈跟踪吗?这将有助于了解错误呼叫的来源。
-
@Devunwired 抱歉耽搁了。我添加了堆栈跟踪。
-
因此请仔细查看该堆栈跟踪并注意此调用与您的
BroadcastReceiver无关。您的代码是从Timer执行的,它从该库内部执行各种线程上的任务。该库直接从后台线程调用侦听器,而不是像 Android 框架那样在主线程上发布回调。
标签: android broadcastreceiver invalidation mapactivity