从服务访问android位置?

Posted

技术标签:

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

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

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

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

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

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

【问题讨论】:

【参考方案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】:

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

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

【讨论】:

以上是关于从服务访问android位置?的主要内容,如果未能解决你的问题,请参考以下文章

Android:位置服务权限

从 Android 中的某个位置访问文件

使用哪个 API 访问 Android 设备上的 GPS 位置? Android API 或 Google 位置服务 API

访问位置服务时,Android 应用缺少状态栏图标

Android - 在后台访问位置而不打开应用程序

从 Android 后台服务问题获取当前位置