Android 尝试从Google云消息更改Google Maps v2 Api上的标记时出现非法状态异常

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

我正在写一个android应用程序,我在谷歌地图上有一个标记,应该改成GCM接收到的位置。 我有一个全局静态列表,其中保存了标记以及id和位置。 当我收到消息时,我可以在我的GCMBaseIntentService中更改列表中对象的位置,但当我想执行以下代码时:

    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
         }
});