【问题标题】:Access android location from service?从服务访问android位置?
【发布时间】:2013-02-08 01:31:08
【问题描述】:

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

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

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

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

请解释为什么会这样? android 是否需要 UI 线程来请求位置?有什么办法可以通过改变我的应用结构来解决吗?

【问题讨论】:

    标签: android android-service android-location


    【解决方案1】:

    Looper 是不断轮询Message's/Runnables 的线程队列(通过该线程上的Handler 发布的那些)。 UI 线程默认有一个。对于自定义线程,您需要在启动线程之前进行设置。

    As mentioned in the example:

    用于为线程运行消息循环的类。线程默认做 没有与之关联的消息循环;创建一个,调用 prepare() 在要运行循环的线程中,然后 loop() 到 让它处理消息直到循环停止。

    现在,RequestLocationUpdates() 需要一种机制来为您的线程提供更新,但您的线程没有 Looper 轮询。

    考虑将RequestLocationUpdates() 及其对应的removeUpdates() 移动到服务线程。最有可能在服务开始和停止的地方。

    【讨论】:

      【解决方案2】:

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

      您的问题的解决方案:

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

      【讨论】:

        【解决方案3】:

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

        这里的服务类:

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

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-04-20
            • 1970-01-01
            • 2019-02-10
            • 1970-01-01
            • 2013-05-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多