Android 尝试从Google云消息更改Google Maps v2 Api上的标记时出现非法状态异常
我正在写一个android应用程序,我在谷歌地图上有一个标记,应该改成GCM接收到的位置。 我有一个全局静态列表,其中保存了标记以及id和位置。 当我收到消息时,我可以在我的GCMBaseIntentService中更改列表中对象的位置,但当我想执行以下代码时:Android 尝试从Google云消息更改Google Maps v2 Api上的标记时出现非法状态异常,android,maps,google-cloud-messaging,illegalstateexception,Android,Maps,Google Cloud Messaging,Illegalstateexception,我正在写一个android应用程序,我在谷歌地图上有一个标记,应该改成GCM接收到的位置。 我有一个全局静态列表,其中保存了标记以及id和位置。 当我收到消息时,我可以在我的GCMBaseIntentService中更改列表中对象的位置,但当我想执行以下代码时: mMarker.setPosition(new LatLng(member.getLatitude(),member.getLongitude())); 我得到以下例外情况: 01-13 18:52:38.118: E
mMarker.setPosition(new LatLng(member.getLatitude(),member.getLongitude()));
我得到以下例外情况:
01-13 18:52:38.118: E/AndroidRuntime(7605): FATAL EXCEPTION: IntentService[GCMIntentService-1041237551356-1]
01-13 18:52:38.118: E/AndroidRuntime(7605): java.lang.IllegalStateException: Not on the main thread
01-13 18:52:38.118: E/AndroidRuntime(7605): at maps.am.r.b(Unknown Source)
01-13 18:52:38.118: E/AndroidRuntime(7605): at maps.ar.d.b(Unknown Source)
01-13 18:52:38.118: E/AndroidRuntime(7605): at maps.y.ae.addMarker(Unknown Source)
01-13 18:52:38.118: E/AndroidRuntime(7605): at com.google.android.gms.maps.internal.IGoogleMapDelegate$Stub.onTransact(IGoogleMapDelegate.java:167)
01-13 18:52:38.118: E/AndroidRuntime(7605): at android.os.Binder.transact(Binder.java:279)
01-13 18:52:38.118: E/AndroidRuntime(7605): at com.google.android.gms.maps.internal.IGoogleMapDelegate$a$a.addMarker(Unknown Source)
01-13 18:52:38.118: E/AndroidRuntime(7605): at com.google.android.gms.maps.GoogleMap.addMarker(Unknown Source)
01-13 18:52:38.118: E/AndroidRuntime(7605): at com.example.MapViewActivity.showMember(MapViewActivity.java:529)
01-13 18:52:38.118: E/AndroidRuntime(7605): at com.example.MapViewActivity.updateMember(MapViewActivity.java:417)
01-13 18:52:38.118: E/AndroidRuntime(7605): at com.example.MapViewActivity.updateMembers(MapViewActivity.java:410)
01-13 18:52:38.118: E/AndroidRuntime(7605): at com.example.pushnotifications.GCMIntentService.onMessage(GCMIntentService.java:75)
01-13 18:52:38.118: E/AndroidRuntime(7605): at com.google.android.gcm.GCMBaseIntentService.onHandleIntent(GCMBaseIntentService.java:223)
01-13 18:52:38.118: E/AndroidRuntime(7605): at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:59)
01-13 18:52:38.118: E/AndroidRuntime(7605): at android.os.Handler.dispatchMessage(Handler.java:99)
01-13 18:52:38.118: E/AndroidRuntime(7605): at android.os.Looper.loop(Looper.java:130)
01-13 18:52:38.118: E/AndroidRuntime(7605): at android.os.HandlerThread.run(HandlerThread.java:60)
我尝试在地图上添加一个按钮来刷新所有标记(使用完全相同的代码),效果很好。
所以,不知何故,问题是GCM是在不同的线程或类似的东西中执行的,似乎我无法从不同的线程更改标记
我尝试了一个丑陋的解决方案:每秒刷新所有标记。
但是,从MapViewActivity创建线程会产生相同的异常:
private Thread MarkerUpdater = new Thread(
new Runnable() {
public void run() {
while(true) {
updateMembers();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
也许有人知道一个好的解决方案会是什么样子?您需要为主UI线程获取处理程序,并在那里发布一个runnable
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable(){
// your UI code here
}
您在Runnable
中从服务中引用的任何变量都必须是最终变量。既然你说你是以全局/静态的方式共享数据,你应该没问题。使用我的代码:
private class UpdateThread extends AsyncTask<Void, Void, Void>
{
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
//...
mMarker.setPosition(new LatLng(member.getLatitude(),member.getLongitude()));
}
@Override
protected Void doInBackground(Void... params) {
while(true)
{
try {
//...
publishProgress();
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
这可能对其他人有用:我只是遇到了一个非常类似的问题,即在接收GCM消息时标记不更新。解决方案确实是将标记更新代码放入主循环处理程序中,但由于某些原因,在run()方法中放入什么并不重要 太长,读不下去了 仅仅把marker.setPosition(lat,lon)调用放在runnable中是不够的。我必须把我所有的标记处理代码放在可运行状态中(查找标记,检查它们是否有位置,设置新位置,更新地图相机) 详细地 问题
- 我的应用程序正在通过GCM接收其他人的位置更新
- 每次位置更新都必须更新相应的标记
- 我的申请收到了第一份GCM,但下一份没有收到
- 没有崩溃,应用程序完全响应,只是在第一次崩溃后没有收到更多的GCM消息
- 我的第一个想法是GCM服务器速度太慢了
- 但是:在监视所有控制台输出时,我看到来自GCM的调试消息,显示消息到达设备上,但不在应用程序中李>
- 确保接收GCM时需要运行的所有Google Maps代码在MainLoop上处于可运行状态
- 将所有GM代码放在可运行状态下是有意义的,但是看到没有错误输出,应用程序完全响应,很难找到解决方案
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
//your code
}
});
万一有人遇到困难,代码示例并不完整,并且有一个小的打字错误。下面是更正后的示例代码:Handler=new Handler(Looper.getMainLooper());post(new Runnable(){@Override public void run(){//您的UI代码在这里}});是的,通过GCM我也有同样的问题。你找到解决办法了吗?
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
//your code
}
});