在Android中的单独线程上使用looper

时间:2015-04-10 12:14:23

标签: java android multithreading

背景

我试图通过handler.postDelayed逐渐移动标记来显示公交车的移动,直到它从一站到达下一站。

我希望它在一段时间后重复下一站,所以我尝试在一个单独的线程上使用一个looper,因为它对主UI线程来说太多了。

问题:

因为我正在更新标记的位置,所以我需要在每秒后为它设置一个新位置,但是在运行代码时我会遇到错误,指出它不在主UI线程上(参见底部的这篇文章)。

错误指向存储busMarker的变量,我假设它只能由创建它的线程修改。

我已经尝试了runOnUiThread(),但我仍然会遇到其他错误,例如因为我为其分配值而不是主线程中的空值。

我假设有一种比连续返回主线程更清洁的方式,那么我该如何实现呢?

创建主题

private class ThreadClass extends Thread {

    @Override
    public void run() {

        Looper.prepare();

        moveBusMarker();

        if (passedStops.size() != stops.size()) {

            Looper.loop();
        }
        else {

            Looper.myLooper().quit();
        }
    }
}

运行主题

    if (passedStops.size() != 0 && passedStops.size() != stops.size()) {
        thread.start();
    }

执行动作

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

记录错误

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)

3 个答案:

答案 0 :(得分:1)

没有办法计算创建handler1变量的线程。确保它在UI线程上。或者快速修复:

handler1 = new Handler(context.getApplicationContext().getMainLooper());

答案 1 :(得分:0)

您的方法moveBusMarker()在后台线程中运行,这就是您收到此错误的原因。 试试AsyncTask课程。使用doInBackground方法运行looper,然后使用postExecute方法更新UI。

答案 2 :(得分:0)

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

应该解决你的问题。