6

我正在编写一个 android 应用程序,我在 Google Map 上有标记,应该将其更改为 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();
                }
            }
        }
    });

也许有人知道一个好的解决方案会是什么样子?

4

4 回答 4

11

您需要获取主 UI 线程的处理程序并在那里发布一个可运行文件。

Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable(){ 
   // your UI code here 
}

您从您的服务中引用的任何变量Runnable都需要是最终的。既然您说您将数据共享为全局/静态,那么您应该没问题。

于 2013-01-13T22:27:17.440 回答
2

试试这个,

Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
         @Override
         public void run() {
              //your code
         }
});
于 2016-04-28T12:44:28.090 回答
1

这可能对其他人有用:我刚刚遇到了一个非常相似的问题,即在收到 GCM 消息时标记不更新。解决方案确实是将标记更新代码放在主循环处理程序中,但由于某种原因,您在该 run() 方法中放入的内容确实很重要。

TLDR

仅仅将 marker.setPosition(lat, lon)-call 放在 runnable 中是不够的。我必须将所有标记处理代码放在可运行文件中(查找标记,检查它们是否有位置,设置新位置,更新地图相机)。

详细地

问题

  • 我的应用通过 GCM 接收其他人的位置更新。
  • 每次更新位置时,都必须更新相应的标记。
  • 我的申请收到了第一个 GCM,但下一个没有。
  • 没有崩溃,应用程序完全响应,只是在第一个之后没有收到更多的 GCM 消息。

我发现了什么

  • 我的第一个想法是 GCM 服务器只是很慢。
  • 但是:在监视所有控制台输出时,我看到来自 GCM 的调试消息显示消息已到达设备,但未到达应用程序!

什么对我有用

  • 确保在接收 GCM 时需要运行的所有Google Maps 代码都在 MainLooper 的 Runnable 中。

结论

  • 将所有 GM 代码放入可运行文件中确实有意义,但是看到没有错误输出并且应用程序完全响应,很难找到该解决方案。
于 2015-11-26T14:50:37.230 回答
0

使用我的代码:

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

    UpdateThread updateThread = new UpdateThread();
    updateThread.execute();
于 2014-11-24T15:51:00.397 回答