Reputation: 43
Background:
I'm trying to show the movement of a bus by incrementally moving a marker via handler.postDelayed
until it reaches from one stop to the next stop.
I want it to repeat for the next stop after a certain amount of time, so I tried using a looper on a separate thread as it was too much work for the main UI thread.
Problem:
Because I am updating the position of a marker, I need to set a new position to it after every second, however when running the code I run across errors stating that it is not on the main UI thread (see the bottom of this post).
The error points to the variable storing the busMarker, which I assume can only be modified by the thread it was created on.
I've tried runOnUiThread()
but i'll still get other errors, such as null values which shouldn't be because I assigned values to them, but only in the main thread.
I'm assuming there is a much cleaner way than having to continuously return to the main thread, so how do I achieve this?
Creating the thread
private class ThreadClass extends Thread {
@Override
public void run() {
Looper.prepare();
moveBusMarker();
if (passedStops.size() != stops.size()) {
Looper.loop();
}
else {
Looper.myLooper().quit();
}
}
}
Running the thread
if (passedStops.size() != 0 && passedStops.size() != stops.size()) {
thread.start();
}
Executing the Movement
// set up a timer
final long limit = TimeUnit.SECONDS.toMillis(seconds) - 1000;
final long startTime = System.currentTimeMillis();
final Stop NextStop = nextStop;
final Handler handler1 = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
Log.d("", "The bus is currently at " + busPosition.toString());
// get the current bus' position
double lat = busPosition.latitude;
double lon = busPosition.longitude;
// add the difference to the bus position to move it closer
lat = lat + latDifference;
lon = lon + lonDifference;
busPosition = new LatLng(lat, lon);
Log.d("", "The bus has moved to " + busPosition.toString());
// set the new position to the marker representing the bus movement
busMarker.setPosition(busPosition);
// it hasn't reached the next stop, continue to animate
if ((System.currentTimeMillis() - startTime) < limit) {
handler1.postDelayed(this, 1000);
}
// else the time is up i.e. the bus has reached the next stop, so set the new target
else {
Log.d("", "The bus has passed " + NextStop.getName());
passedStops.add(NextStop);
Log.d("", passedStops.toString());
createPolyline();
}
}
};
handler1.post(runnable);
The error logged
Process: com.example.sanj.fyp, PID: 18904
java.lang.IllegalStateException: Not on the main thread
at com.google.l.a.cd.b(Unknown Source)
at com.google.maps.api.android.lib6.c.ca.a(Unknown Source)
at com.google.maps.api.android.lib6.c.aj.a(Unknown Source)
at com.google.android.gms.maps.model.internal.t.onTransact(SourceFile:73)
at android.os.Binder.transact(Binder.java:361)
at com.google.android.gms.maps.model.internal.l$a$a.setPosition(Unknown Source)
at com.google.android.gms.maps.model.Marker.setPosition(Unknown Source)
at com.example.sanj.fyp.main.fragment.LiveServiceFragment$2$1.run(LiveServiceFragment.java:423)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at com.example.sanj.fyp.main.fragment.LiveServiceFragment$ThreadClass.run(LiveServiceFragment.java:115)
Upvotes: 0
Views: 704
Reputation: 81539
Handler handler = new Handler(Looper.getMainLooper());
is ought to fix your problem.
Upvotes: 0
Reputation: 974
There's no way to figure what thread your handler1 variable is created from. Make sure that it's on the UI thread. Or quickfix:
handler1 = new Handler(context.getApplicationContext().getMainLooper());
Upvotes: 1