Доступ к местоположению Android из службы?

У меня проблема с запросом обновлений местоположения из потока, запущенного службой.

Мое приложение должно получать обновления местоположения из фоновой службы (без какого-либо потока пользовательского интерфейса). Я объясню структуру моего приложения.

  1. У него есть служба, запущенная Boot Receiver.
  2. В сервисе onStartCommand() он запускает поток планировщика.
  3. Поток планировщика запрашивает обновления местоположения.

Проблема в том, что когда планировщик вызывает locationMgr.requestLocationUpdates(), он говорит Can't create handler inside thread that has not called Looper.prepare() Я видел подобные проблемы для других, но не могу найти никакого решения. Я слышал, что мы можем звонить напрямую из службы, чтобы получать обновления местоположения без каких-либо проблем, но, поскольку я не могу найти способ приостановить службу (например, поток планировщика), я думаю, мне нужен отдельный поток.

Пожалуйста, объясните, почему это происходит? Требует ли Android поток пользовательского интерфейса для запроса местоположения? Есть ли решение, изменив структуру моего приложения?


person Arun Babu    schedule 22.02.2013    source источник


Ответы (4)


Looper — это то, что продолжает опрашивать очередь потоков для Message/Runnable (тех, которые были опубликованы через Handler в этом потоке). Поток пользовательского интерфейса имеет один по умолчанию. Для пользовательских потоков вам необходимо настроить его перед запуском потока.

Как указано в примере:

Класс, используемый для запуска цикла сообщений для потока. Потоки по умолчанию не имеют связанного с ними цикла сообщений; чтобы создать его, вызовите prepare() в потоке, который должен запустить цикл, а затем loop(), чтобы он обрабатывал сообщения до тех пор, пока цикл не будет остановлен.

Теперь RequestLocationUpdates() нужен механизм для доставки обновлений в ваш поток, но в вашем потоке нет Looper опроса.

Рассмотрите возможность перемещения RequestLocationUpdates() и соответствующего ему removeUpdates() в поток службы. Скорее всего, где служба начинается и останавливается.

person S.D.    schedule 22.02.2013

Причина этого: getLooper подключен к пользовательскому интерфейсу контекста, но сервисный процесс не подключается напрямую к пользовательскому интерфейсу. Итак, вы получаете ошибку.

решение для вашей проблемы:

1) поместите классы местоположения в другой пакет. 2) Импортируйте это имя пакета. 3) Используйте один интерфейс обратного вызова в вашем пакете. 4) используйте экземпляр интерфейса в своем сервисном компоненте. 5) Это будет работать!!

person Naveen AH    schedule 22.02.2013

Я использовал это и отлично работает: чтобы получить местоположение в службе

Класс обслуживания здесь:

public class MyService extends Service {

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();

    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub
        super.onStart(intent, startId);

        // start location manager
        LocationDetermined objLocationDetemined = new LocationDetermined(this);
        objLocationDetemined.getlocation(this);
        objLocationDetemined.getRecentKnownLocation(this);

    }

Класс расположения здесь:

public class LocationDetermined implements OnInitListener {

    String TAG = "LocationDeterminedClass";
private static LocationManager locationManager;
double Lat = 0.0;
double Long = 0.0;
GeoPoint geoPoint;
private Toast mToast;
Context appContext;
static MyLocationListener locationListener;

    public LocationDetermined(Context context) {
        this.appContext = context;

    }

    public MyLocationListener getlocation(Context appContext) {

        locationManager = (LocationManager) appContext
                .getSystemService(Context.LOCATION_SERVICE);
        locationListener = new MyLocationListener();
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_COARSE);
        String provider = locationManager.getBestProvider(criteria, true);

        Log.d(TAG, "------provider------" + provider);


        if (provider != null && locationManager.isProviderEnabled(provider)) {
            locationManager.requestLocationUpdates(provider, 0, 0,
                    locationListener);
        } else {
            Toast.makeText(appContext, "No provider available to get loctaion",
                    2000).show();
        }
        return locationListener;
    }



    private class MyLocationListener implements LocationListener {

        public void onProviderDisabled(String provider) {
            // TODO Auto-generated method stub

        }

        public void onProviderEnabled(String provider) {
            // TODO Auto-generated method stub

        }

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

        }

        public void onLocationChanged(final Location argLocation) {
            // TODO Auto-generated method stub
            if (argLocation != null) {
                Lat = argLocation.getLatitude();
                Long = argLocation.getLongitude();

                Log.e("OnLocationChanged:", "lat:" + Lat + "  long:" + Long);

                Log.d("service gps", "lat" + argLocation.getLatitude() + "-"
                        + argLocation.getLongitude());

                Constant.mLatitude = argLocation.getLatitude();
                Constant.mLongitude = argLocation.getLongitude();               
            }
        }
    }

    public GeoPoint getRecentKnownLocation(Context appContext) {
        Location locGps = locationManager
                .getLastKnownLocation(LocationManager.GPS_PROVIDER);
        Location locNet = locationManager
                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

        Location locPassive = locationManager
                .getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
        if (locGps != null) {
            Lat = locGps.getLatitude();
            Long = locGps.getLongitude();

            Constant.mLatitude = locGps.getLatitude();
            Constant.mLongitude = locGps.getLongitude();

            geoPoint = new GeoPoint((int) (Lat * 1000000),
                    (int) (Long * 1000000));
            return geoPoint;

        } else if (locNet != null) {
            Lat = locNet.getLatitude();
            Long = locNet.getLongitude();

            Constant.mLatitude = locNet.getLatitude();
            Constant.mLongitude = locNet.getLongitude();

            geoPoint = new GeoPoint((int) (Lat * 1000000),
                    (int) (Long * 1000000));
            return geoPoint;

        }
        return geoPoint;
    }

    private void fetchedSavedLocationDetail(Context mContext) {

    }

    @Override
    public void onInit(int status) {
        // TODO Auto-generated method stub

    }

    public static void removeLocationListener() {

        locationManager.removeUpdates(locationListener);
    }

}

Я использовал эти переменные в классе Constants для хранения местоположения public static double mLatitude = 0.0, mLongitude = 0.0;

запустить службу startService(new Intent(this, MyService.class));

person Manmeet Singh Batra    schedule 22.02.2013

Я исправил это с помощью обработчика.

  1. Я создал обработчик.
  2. Я поместил сервисный код в его handleMessage()
  3. Создайте поток, который отправляет пустое сообщение обработчику с требуемым интервалом (цикл while).
  4. Поэтому, когда обработчик получает пустое сообщение, он запускает handleMessage(), который содержит фактический цикл планировщика.
person Arun Babu    schedule 22.02.2013