1

我从服务启动的线程请求位置更新时遇到问题。

我的应用程序需要从后台服务获取位置更新(没有任何 UI 线程)。我将解释我的应用程序的结构。

  1. 它有一个由 Boot Receiver 启动的服务。
  2. onStartCommand()服务中,它启动一个调度线程。
  3. 调度程序线程请求位置更新。

问题是当调度程序调用locationMgr.requestLocationUpdates() 它说Can't create handler inside thread that has not called Looper.prepare() 我已经看到其他人的类似问题但找不到任何解决方案。我听说我们可以直接从服务调用以获取位置更新而没有任何问题,但由于我找不到让服务休眠的方法(如调度程序线程),我想我需要一个单独的线程。

请解释为什么会这样?android 是否需要 UI 线程来请求位置?通过更改我的应用程序结构有什么解决方案吗?

4

4 回答 4

2

Looper is what keeps polling a thread queue for Message's/Runnables (those posted via a Handler on that thread). UI thread has one by default. For custom threads, you need to set it up before you start the thread.

As mentioned in the example:

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

Now, RequestLocationUpdates() needs a mechanism to deliver updates to your thread, but your thread doesn't have a Looper polling.

Consider Moving RequestLocationUpdates() and its corresponding removeUpdates() to Service thread. Most likely where service starts and stops.

于 2013-02-22T12:25:19.250 回答
1

我已经使用了它并且工作正常:获取服务位置

这里的服务等级:

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

}

我在常量类中使用这些变量来存储位置 public static double mLatitude = 0.0, mLongitude = 0.0;

启动服务 startService(new Intent(this, MyService.class));

于 2013-02-22T12:46:34.650 回答
1

发生的原因是:getLooper 连接到 context 的 UI,但是 service 是 ackground 进程没有直接连接到 UI。所以你得到错误。

您的问题的解决方案:

1)将位置类放在其他包中。2)导入该包名称。3) 在你的包中使用一个回调接口。4)在你的服务组件中使用接口实例。5)它会工作!

于 2013-02-22T12:19:31.677 回答
0

我已经通过使用处理程序修复了它。

  1. 我创建了一个处理程序。
  2. 我把服务代码放在它的handleMessage()
  3. 创建一个线程,以所需的时间间隔(while 循环)向处理程序发送空消息。
  4. 因此,当处理程序接收到空消息时,它会运行handleMessage()包含实际调度程序循环的
于 2013-02-22T13:48:33.970 回答