简体   繁体   中英

Using a looper on a separate thread in Android

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)

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

Your method moveBusMarker() is run in the background thread that's why you get this error. Try the AsyncTask class. Use the doInBackground method to run your looper and then update the UI in the postExecute method.

 Handler handler = new Handler(Looper.getMainLooper());

应该解决您的问题。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM