问题
I am writing an android app and I have markers on a Google Map that should be changed to a position that I receive by GCM. I have a global static List in which I save the marker together with an id and the position. I can change the positions of the Objects in the list in my GCMBaseIntentService when I receive a message, but when I want to execute the following code:
mMarker.setPosition(new LatLng(member.getLatitude(),member.getLongitude()));
I get the following Exception:
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)
I tried adding a button to the map that refreshes all markers (with exactly the same code) and that works fine. So somehow the problem is that the GCM is executed in a different thread or something like that and it seems that I cannot change markers from a different thread...
I tried an ugly solution: To refresh all markers every second. But creating a thread from the MapViewActivity gives the same exception:
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();
}
}
}
});
Maybe someone has an idea how a nice solution could look like?
回答1:
You need to get the handler for your main UI thread and post a runnable there.
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable(){
// your UI code here
}
Any variables you reference from your service in your Runnable
will need to be final. Since you said you are sharing the data as global/static, you should be okay.
回答2:
This might be useful for someone else: I just had a very similar problem of markers not updating when receiving a GCM message. The solution is indeed to put the marker update code in a main loop handler, but for some reason it does matter what you put in that run()-method.
TLDR
Just putting the marker.setPosition(lat, lon)-call in the runnable wasn't enough. I had to put all of my marker handling code in the runnable (finding the markers, checking if they have a position, setting the new position, updating the map camera).
In detail
The problem
- My app was receiving location updates from someone else via GCM.
- With every location update, the coresponding marker had to be updated.
- The first GCM was received by my application, but the next ones weren't.
- No crashes, and the application was fully responsive, just no more GCM messages received after the first one.
What I discovered
- My first thought was that the GCM server was just being slow.
- But: While monitoring all console output I saw debug messages from GCM showing that the messages were arriving on the device, but not in the app!
What worked for me
- Make sure all Google Maps code that needs to run when receiving the GCM is in a Runnable on the MainLooper.
Conslusion
- It does make sense to put all GM code in a runnable, but seeing that there was no error output and the app was completely responsive it was very hard to discover that solution.
回答3:
Use my code:
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();
回答4:
Try this,
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
//your code
}
});
来源:https://stackoverflow.com/questions/14308789/illegal-state-exception-when-trying-to-change-a-marker-on-a-google-maps-v2-api-f