Исключение Looper.prepare с использованием LocationManager во внешней службе

Я получаю следующее исключение, когда пытаюсь использовать LocationManager в пользовательском классе, работающем во внешней службе:

*** Uncaught remote exception!  (Exceptions are not yet supported across        processes.)
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
        at android.os.Handler.<init>(Handler.java:200)
        at android.os.Handler.<init>(Handler.java:114)
        at android.location.LocationManager$GpsStatusListenerTransport$1.<init>(LocationManager.java:1464)
        at android.location.LocationManager$GpsStatusListenerTransport.<init>(LocationManager.java:1464)
        at android.location.LocationManager.addGpsStatusListener(LocationManager.java:1503)
        at org.poseidon_project.contexts.hardware.GPSIndoorOutdoorContext.start(GPSIndoorOutdoorContext.java:97)
        at org.poseidon_project.context.management.ContextManager.addObserverRequirement(ContextManager.java:97)
        at org.poseidon_project.context.reasoner.ContextMapper.registerIndoorOutdoorsContext(ContextMapper.java:260)
        at org.poseidon_project.context.reasoner.ContextMapper.registerContext(ContextMapper.java:197)
        at org.poseidon_project.context.ContextReasonerCore.addContextRequirement(ContextReasonerCore.java:70)
        at org.poseidon_project.context.ContextReasonerService$1.addContextRequirement(ContextReasonerService.java:74)
        at org.poseidon_project.context.IContextReasoner$Stub.onTransact(IContextReasoner.java:74)
        at android.os.Binder.execTransact(Binder.java:446)

Теперь я прочитал много ответов, касающихся использования Looper, с такими вещами, как:

    Looper.prepare;
    mLocationManager.requestLocationUpdates(mProvider, mMinTime, mMinDistance, this, Looper.getMainLooper);

Но в конечном итоге это не приводит к вызову обратного вызова (onLocationChanged (местоположение)) при обновлении?

Класс реализует LocationListener, который также вызывает методы LocatioManager:

public abstract class LocationContext extends ContextObserver implements LocationListener {

protected LocationManager mLocationManager;
private int mMinTime = 3000;
private int mMinDistance = 10;
private String mProvider = LocationManager.GPS_PROVIDER;
private String mIdealProvider = LocationManager.GPS_PROVIDER;


public LocationContext (Context c) {
    super(c);
    mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}

public LocationContext (Context c, ContextReceiver cr) {
    super(c, cr);
    mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}

public LocationContext (Context c, ContextReceiver cr, int minTime, int minDistance, String name) {
    super(c, cr, name);
    mMinTime = minTime;
    mMinDistance = minDistance;
    mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}

public LocationContext (Context c, ContextReceiver cr, int minTime, int minDistance, String provider, String name) {
    super(c, cr, name);
    mMinTime = minTime;
    mMinDistance = minDistance;
    mProvider = provider;
    mIdealProvider = provider;
    mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
}

@Override
public boolean start() {

    //new Thread(new Runnable() {
    //  @Override
    //  public void run() {
            //Looper.prepare();

            mLocationManager.requestLocationUpdates(mProvider, mMinTime, mMinDistance, this);
            //handler.sendEmptyMessage(0);
            //Looper.loop();
    //  }
    //}).start();


    mIsRunning = true;
    //Looper.loop();
    return true;
}


@Override
public boolean pause() {
    return stop();
}


@Override
public boolean resume() {
    return start();
}

@Override
public boolean stop() {
    mLocationManager.removeUpdates(this);
    mIsRunning = false;
    return true;
}

@Override
public void onLocationChanged(Location location) {
    checkContext(location);

}


protected abstract void checkContext(Location location);

@Override
public void onProviderDisabled(String provider) {
    if (provider.equals(mIdealProvider)) {
        mProvider = LocationManager.GPS_PROVIDER;

        if (! mLocationManager.isProviderEnabled(mProvider)) {
            Intent gpsOptionIntent = new Intent (android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            mContext.startActivity(gpsOptionIntent);
        }
    }

}


@Override
public void onProviderEnabled(String provider) {
    if ((provider.equals(mIdealProvider)) && (! provider.equals(mProvider))) {
        mLocationManager.removeUpdates(this);
        mProvider = provider;
        mLocationManager.requestLocationUpdates(mProvider, mMinTime, mMinDistance, this);
    }
}


@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
    // TODO Auto-generated method stub

}

public int getMinTime() {
    return mMinTime;
}

public void setMinTime(int mMinTime) {
    this.mMinTime = mMinTime;
}

public int getMinDistance() {
    return mMinDistance;
}

public void setMinDistance(int mMinDistance) {
    this.mMinDistance = mMinDistance;
}

Я не очень понимаю, как использовать Looper в моей ситуации. Кто-нибудь может помочь? Я понимаю ответ «запустить в потоке пользовательского интерфейса», но это одно сервисное приложение, пользовательского интерфейса нет, поэтому я не думаю, что смогу сделать это в потоке пользовательского интерфейса?

****ОБНОВЛЕНИЕ******Решение найдено******

Я считаю, что нашел решение. Рассматриваемый класс был абстрактным классом, который я расширил несколькими классами, которые выполняли различные операции на основе местоположения.

В абстрактном классе LocationContext я использовал:

 mLocationManager.requestLocationUpdates(mProvider, mMinTime, mMinDistance,this, Looper.getMainLooper());

И в классе реализации (например, для анализа состояния спутников GPS) я поместил его в новую тему:

new Thread(new Runnable() {
        @Override
        public void run() {
            Looper.prepare();
            GPSIndoorOutdoorContext.super.start();
            mLocationManager.addGpsStatusListener(gpsListener);
            Looper.loop();
        }
    }).start();

person user3587258    schedule 13.05.2015    source источник


Ответы (1)


mLocationManager.requestLocationUpdates(mProvider, mMinTime, mMinDistance, this);

вызывается из потока NON UI. Убедитесь, что вы вызываете свой init или вызываете свой метод в потоке пользовательского интерфейса. Вы, вероятно, инициируете LocationContext или вызываете метод start из потока НЕ ​​пользовательского интерфейса, чего вы не можете сделать. Чтобы запросить обновления местоположения, его необходимо вызвать из потока пользовательского интерфейса.

person Carnal    schedule 13.05.2015
comment
Проблема в том, что это сервис, который работает без пользовательского интерфейса. Предполагается, что это служба, которую вызывают другие приложения (с пользовательским интерфейсом). Я не знаю, как я могу сделать это в потоке пользовательского интерфейса? Этот код отлично работает, если я пробую его с тестовой активностью в том же приложении, но когда он вызывается из другого приложения, возникает исключение. - person user3587258; 13.05.2015
comment
Я не понимаю, как я могу, как я уже сказал, эта служба обычно находится в отдельном процессе для любого приложения с действием. runOnUIThread - это метод Activity... Есть ли способ использовать Looper, чтобы обойти это? - person user3587258; 14.05.2015