EventBus不在主线程上

时间:2015-03-13 19:21:19

标签: android google-maps android-fragments greenrobot-eventbus

我正在尝试从我的WS获取位置并在我的GoogleMap片段中更新我的标记,所以我正在做的是:

我的HomeActivity包含2个片段(2个GoogleMaps,其中一个有TileOverlay)。

在我的GoogleMap片段中,我试图从OnCameraChangeListener获取我的标记位置,以便在用户移动时添加标记。

我正在使用EventBus和Okhttp进行异步请求!

我的GoogleMapFragment:

public class GoogleMapFragment extends FragmentBase {

@Override
public void onResume() {
    mapView.onResume();
    BusHelper.register(this); // Register the EventBus with my helper
    super.onResume();
}

@Override
public void onPause() {
    BusHelper.unregister(this); // Unregister the EventBus with my helper
    super.onPause();
}

public GoogleMap.OnCameraChangeListener getCameraChangeListener() {
    return new GoogleMap.OnCameraChangeListener() {
        @Override
        public void onCameraChange(CameraPosition cameraPosition) {

           //those are corners of visible region
            VisibleRegion visibleRegion = mMap.getProjection().getVisibleRegion();
            LatLng farLeft = visibleRegion.farLeft;
            LatLng farRight = visibleRegion.farRight;
            LatLng nearLeft = visibleRegion.nearLeft;
            LatLng nearRight = visibleRegion.nearRight;

            double minY = nearLeft.latitude;
            double minX = nearLeft.longitude;
            double maxY = farRight.latitude;
            double maxX = farRight.longitude;

            //Send the WS Request to a manager who uses okhttp              
            ApiManager.getPositions(minX, minY, maxX, maxY);
        }
    };
}

//Receive the eventBus event
public void onEvent(GetPositionsEvent event) {
    if (event.positions != null)
        setMarkersByVisibleRegion(event.positions);
}

在此之后它将在APIManager中执行WS请求。

public class IMSApiManager {
private final static Gson gson = new Gson();
private static Positions mPositions;

/**
 * @return Positions
 */
public static void getPositions(double minX, double minY, double maxX, double maxY) {
    String TAG = "getPositions";

    String wSRequest = AppConstants.REQUEST_POSITIONS
            .replace("{vUser}", "CARREPH1")
            .replace("{vMinX}", new BigDecimal(minX).toPlainString())
            .replace("{vMinY}", new BigDecimal(minY).toPlainString())
            .replace("{vMaxX}", new BigDecimal(maxX).toPlainString())
            .replace("{vMaxY}", new BigDecimal(maxY).toPlainString());

    try {
        RestAsyncHttpClient.doGetRequest(wSRequest, new GetPositionsCallback() {
            @Override
            public void onFailure(Request request, IOException e) {
                super.onFailure(request, e);
            }

            @Override
            public void onResponse(Response response) throws IOException {
                super.onResponse(response);
                mPositions = gson.fromJson(response.body().charStream(), Positions.class);
                BusHelper.post(new GetPositionsEvent(mPositions)); //Post the eventBus
            }
        });

    } catch (IOException exp) {
        LogHelper.error(TAG, "Error getting positions", exp);
    }
}

}

我熟悉不在mainThread上的错误,但从理论上讲这将是可能的,如果不是我可以在不执行片段的新实例的情况下添加标记。

4 个答案:

答案 0 :(得分:17)

Accepted answer only works for versions lower than third, for other versions you should use threadMode = ThreadMode.MAIN (documentation)

List<Foo> foos = cache.FindAll(x => x.Name == "bar");

答案 1 :(得分:2)

当您尝试将对象发布到后台线程中的EventBus时,您会收到错误。解决方法是,如果在后台线程中调用post(...),让Handler将其移动到主线程。

覆盖您的BusHelper post(...)方法并执行以下操作。

public class BusHelper extends Bus {

    ...

    private final Handler mHandler = new Handler(Looper.getMainLooper());

    @Override
    public void post(final Object event) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            super.post(event);
        } else {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    BusHelper.super.post(event);
                }
            });
        }
    }

    ...

}

希望这有帮助。

答案 2 :(得分:2)

只需使用onEventMainThread而不是onEvent。它也解决了我的问题。

// Called in Android UI's main thread
public void onEventMainThread(MessageEvent event) {
    textField.setText(event.message);
}

为什么呢? 因为在同一个线程中调用onEvent,所以需要在MainThread上运行代码。

答案 3 :(得分:0)

您可以在eventbus的对象上调用post(当后台线程成功时)。 post的参数是任何类的对象,因此根据您的要求设计一个自定义类,它将保存后台线程的结果。

现在在活动上(需要完成UI工作),只需定义:

public void onEventMainThread(final CobbocEvent event)
{  
    if (event.getType() == CobbocEvent.POSITION)
    {  //If background work is success
        if (event.getStatus())
        {
           //Do UI Stuff on main thread
        }
    }
}

CobbocEvent是用于存储后台线程结果数据的自定义类。:

public class CobbocEvent{
 public CobbocEvent(int type) {
    this(type, true, null);
}

public CobbocEvent(int type, boolean status) {
    this(type, status, null);
}

public CobbocEvent(int type, boolean status, Object value) {
    TYPE = type;
    STATUS = status;
    VALUE = value;
}
public CobbocEvent(int type, boolean status, int value) {
    TYPE = type;
    STATUS = status;
    VALUE = value;
}
....

我相信你能得到图片:)