位置侦听器从服务而不是 IntentService 工作

Posted

技术标签:

【中文标题】位置侦听器从服务而不是 IntentService 工作【英文标题】:Location listener works from a Service but not an IntentService 【发布时间】:2013-11-27 12:56:37 【问题描述】:

我有一个应用程序,我试图定期获取用户位置并发送到服务器。我有一个附加到AlarmManager 的服务,它每分钟执行一次(用于测试)。该服务正确找到用户位置并注销 GPS 坐标。一旦有 GPS 锁定,我就会取消定位请求并停止服务。当我要求位置更新时,我会启动一个 Handler,它会在 20 秒后执行,这个 Handler 会删除位置更新并停止 Service,以防没有锁定。这一切都有效。

下面是使用Service 类的代码。

public class TrackingService extends Service 

    private static final String TAG = TrackingService.class.getSimpleName();
    LocationManager             mlocManager;
    LocationListener            mlocListener;
    NfcScannerApplication       nfcscannerapplication;
    String carerID;

    Handler endServiceHandler;
    Runnable endServiceRunnable;

    @Override
    public void onCreate() 
        super.onCreate();

        nfcscannerapplication = (NfcScannerApplication) getApplication();
        mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mlocListener = new MyLocationListener();

        Log.e(TAG, "Service created and location manager and listener created");

    

    @Override
    public void onDestroy() 
        super.onDestroy();
        Log.e(TAG, "in onDestroy in LocationService class");
        mlocManager.removeUpdates(mlocListener);


    

    @Override
    public void onStart(Intent intent, int startId) 
        super.onStart(intent, startId);
        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
        Log.e(TAG, "requesting location updates");

        enableMenuButtonsHandler();
        endServiceHandler.postDelayed(endServiceRunnable,20 * 1000);
    

    @Override
    public IBinder onBind(Intent intent) 
        return null;
    

    private class MyLocationListener implements LocationListener 

        @Override
        public void onLocationChanged(Location loc) 


            Log.e(TAG, "in TrackingService onlocationChanged and about to send lon/lat " + loc.getLongitude() + " " + loc.getLatitude());


            DateTime dt = new DateTime();
            DateTimeFormatter df3 = DateTimeFormat.forPattern("yyyy-MM-dd H:mm:ss.SSS");
            String formattedNowTime3 = df3.print(dt);
            Log.e(TAG, "Time of location fix in TrackingServive = " + formattedNowTime3);


            Cursor c = nfcscannerapplication.loginValidate.queryAllFromCarer();

            if (c.getCount() > 0) 
                if(c.moveToLast())

                carerID = c.getString(c.getColumnIndex(LoginValidate.C_CARER_ID));

                
            

             Log.e(TAG, "carer ID = " + carerID);

             mlocManager.removeUpdates(mlocListener);
             Log.e(TAG, "removed updates(TrackingService)");

             TrackingService.this.stopSelf();
             Log.e(TAG, "called stopSelf on TrackingService");

        

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

        

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

        

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

        

    // end of MyLocationListener


    public void enableMenuButtonsHandler() 

        endServiceHandler = new Handler();
        endServiceRunnable = new Runnable() 
            public void run() 

                endService();

            

            private void endService() 

                 mlocManager.removeUpdates(mlocListener);
                 Log.e(TAG, "removed updates(TrackingService) from the endService handler");

                 TrackingService.this.stopSelf();
                 Log.e(TAG, "called stopSelf on TrackingService from the endService handler");

            
        ;

    


// end of service 

我遇到的问题是,一旦我有 GPS 锁定,我想将经纬度坐标发送到服务器。我知道我可以从Service 使用AsyncTask,但我不想这样做。我更喜欢使用IntentService,因为它在自己的后台线程中运行。这样我就可以直接从IntentService 进行网络调用。

以下代码实现了IntentService 类,但它似乎没有获得锁。 GPS 会无限期地在手机上闪烁。日志语句一直到“请求位置更新”,然后就没有了。

有没有人知道为什么没有锁定?提前致谢。

public class TrackingService extends IntentService 

   private static final String TAG = TrackingService.class.getSimpleName();
   LocationManager             mlocManager;
   LocationListener            mlocListener;
   NfcScannerApplication       nfcscannerapplication;
   String carerID;

   Handler endServiceHandler;
   Runnable endServiceRunnable;

    public TrackingService() 
        super("TrackingService");

    

    @Override
    protected void onHandleIntent(Intent intent) 

           nfcscannerapplication = (NfcScannerApplication) getApplication();
           mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
           mlocListener = new MyLocationListener();
           Log.e(TAG, "Service created and location manager and listener created");

           mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
           Log.e(TAG, "requesting location updates");

           enableMenuButtonsHandler();
           endServiceHandler.postDelayed(endServiceRunnable,20 * 1000);

    



     private class MyLocationListener implements LocationListener 

                 @Override
                 public void onLocationChanged(Location loc) 


                    Log.e(TAG, "in TrackingService onlocationChanged and about to send lon/lat " + loc.getLongitude() + " " + loc.getLatitude());


                     DateTime dt = new DateTime();
                     DateTimeFormatter df3 = DateTimeFormat.forPattern("yyyy-MM-dd H:mm:ss.SSS");
                     String formattedNowTime3 = df3.print(dt);
                     Log.e(TAG, "Time of location fix in TrackingServive = " + formattedNowTime3);


                     Cursor c = nfcscannerapplication.loginValidate.queryAllFromCarer();

                    if (c.getCount() > 0) 
                        if(c.moveToLast())

                        carerID = c.getString(c.getColumnIndex(LoginValidate.C_CARER_ID));

                        
                    

                     Log.e(TAG, "carer ID = " + carerID);

                     mlocManager.removeUpdates(mlocListener);
                     Log.e(TAG, "removed updates(TrackingService)");

                     TrackingService.this.stopSelf();
                     Log.e(TAG, "called stopSelf on TrackingService");

                 

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

                 

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

                 

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

                 

             // end of MyLocationListener


     public void enableMenuButtonsHandler() 

                endServiceHandler = new Handler();
                endServiceRunnable = new Runnable() 
                    public void run() 

                        endService();

                    

                    private void endService() 

                         mlocManager.removeUpdates(mlocListener);
                         Log.e(TAG, "removed updates(TrackingService) from the endService handler");

                         TrackingService.this.stopSelf();
                         Log.e(TAG, "called stopSelf on TrackingService from the endService handler");

                    
                ;

     

//end of trackingService

[编辑1]

public class TrackingService extends Service 

    private static final String TAG = TrackingService.class.getSimpleName();
    LocationManager             mlocManager;
    LocationListener            mlocListener;
    NfcScannerApplication       nfcscannerapplication;
    String carerID;

    Handler endServiceHandler;
    Runnable endServiceRunnable;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 


        nfcscannerapplication = (NfcScannerApplication) getApplication();
        mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mlocListener = new MyLocationListener();

        Log.e(TAG, "Service created and location manager and listener created");

        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
        Log.e(TAG, "requesting location updates");

        enableMenuButtonsHandler();
        endServiceHandler.postDelayed(endServiceRunnable, 20 * 1000);

            return super.onStartCommand(intent, flags, startId);
    



    @Override
    public void onDestroy() 
        super.onDestroy();
        Log.e(TAG, "in onDestroy in LocationService class");
        mlocManager.removeUpdates(mlocListener);


    








    @Override
    public IBinder onBind(Intent intent) 
        return null;
    

    private class MyLocationListener implements LocationListener 

        @Override
        public void onLocationChanged(Location loc) 


            Log.e(TAG, "in TrackingService onlocationChanged and about to send lon/lat " + loc.getLongitude() + " " + loc.getLatitude());


            DateTime dt = new DateTime();
            DateTimeFormatter df3 = DateTimeFormat.forPattern("yyyy-MM-dd H:mm:ss.SSS");
            String formattedNowTime3 = df3.print(dt);
            Log.e(TAG, "Time of location fix in TrackingServive = " + formattedNowTime3);


            Cursor c = nfcscannerapplication.loginValidate.queryAllFromCarer();

            if (c.getCount() > 0) 
                if(c.moveToLast())

                carerID = c.getString(c.getColumnIndex(LoginValidate.C_CARER_ID));

                
            

             Log.e(TAG, "carer ID = " + carerID);

             mlocManager.removeUpdates(mlocListener);
             Log.e(TAG, "removed updates(TrackingService)");

             TrackingService.this.stopSelf();
             Log.e(TAG, "called stopSelf on TrackingService");

        

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

        

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

        

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

        

    // end of MyLocationListener


    public void enableMenuButtonsHandler() 

        endServiceHandler = new Handler();
        endServiceRunnable = new Runnable() 
            public void run() 

                endService();

            

            private void endService() 

                 mlocManager.removeUpdates(mlocListener);
                 Log.e(TAG, "removed updates(TrackingService) from the endService handler");

                 TrackingService.this.stopSelf();
                 Log.e(TAG, "called stopSelf on TrackingService from the endService handler");

            
        ;

    


// end of service 

[编辑2]

@Override
    public int onStartCommand(Intent intent, int flags, int startId) 


        nfcscannerapplication = (NfcScannerApplication) getApplication();
        mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mlocListener = new MyLocationListener();
        Log.e(TAG, "Service created and location manager and listener created");


            HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
            handlerThread.start();
            Looper looper = handlerThread.getLooper();

            Handler handler = new Handler(looper);

        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener, looper);
        Log.e(TAG, "requesting location updates");

        enableMenuButtonsHandler();
        endServiceHandler.postDelayed(endServiceRunnable, 20 * 1000);

            return super.onStartCommand(intent, flags, startId);
    

[编辑3]

public class TrackingService extends Service 

    private static final String TAG = TrackingService.class.getSimpleName();
    LocationManager             mlocManager;
    LocationListener            mlocListener;
    NfcScannerApplication       nfcscannerapplication;
    String carerID;

    Handler endServiceHandler;
    Runnable endServiceRunnable;
    HandlerThread handlerThread;
    Looper looper;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 


        nfcscannerapplication = (NfcScannerApplication) getApplication();
        mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mlocListener = new MyLocationListener();
        Log.e(TAG, "Service created and location manager and listener created");


            Log.e(TAG, "creating handlerthread and looper");
            handlerThread = new HandlerThread("MyHandlerThread");
            handlerThread.start();
            looper = handlerThread.getLooper();





        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener, looper);
        Log.e(TAG, "requesting location updates");

        enableMenuButtonsHandler();
        endServiceHandler.postDelayed(endServiceRunnable, 20 * 1000);

            return super.onStartCommand(intent, flags, startId);
    



    @Override
    public void onDestroy() 
        super.onDestroy();
        Log.e(TAG, "in onDestroy in LocationService class");
        mlocManager.removeUpdates(mlocListener);


    







    @Override
    public IBinder onBind(Intent intent) 
        return null;
    

    private class MyLocationListener implements LocationListener 

        @Override
        public void onLocationChanged(Location loc) 


            Log.e(TAG, "in TrackingService onlocationChanged and about to send lon/lat " + loc.getLongitude() + " " + loc.getLatitude());


            DateTime dt = new DateTime();
            DateTimeFormatter df3 = DateTimeFormat.forPattern("yyyy-MM-dd H:mm:ss.SSS");
            String formattedNowTime3 = df3.print(dt);
            Log.e(TAG, "Time of location fix in TrackingServive = " + formattedNowTime3);


            Cursor c = nfcscannerapplication.loginValidate.queryAllFromCarer();

            if (c.getCount() > 0) 
                if(c.moveToLast())

                carerID = c.getString(c.getColumnIndex(LoginValidate.C_CARER_ID));

                
            

             Log.e(TAG, "carer ID = " + carerID);

             nfcscannerapplication.loginWebservice.sendCarerLocation(carerID, formattedNowTime3, String.valueOf(loc.getLatitude()), String.valueOf(loc.getLongitude()));



             Log.e(TAG, "quiting handlerthread");
             handlerThread.quit();

             mlocManager.removeUpdates(mlocListener);
             Log.e(TAG, "removed updates(TrackingService)");

             TrackingService.this.stopSelf();
             Log.e(TAG, "called stopSelf on TrackingService");

        

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

        

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

        

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

        

    // end of MyLocationListener


    public void enableMenuButtonsHandler() 

        endServiceHandler = new Handler();
        endServiceRunnable = new Runnable() 
            public void run() 

                endService();

            

            private void endService() 

                 mlocManager.removeUpdates(mlocListener);
                 Log.e(TAG, "removed updates(TrackingService) from the endService handler");

                 TrackingService.this.stopSelf();
                 Log.e(TAG, "called stopSelf on TrackingService from the endService handler");

                 Log.e(TAG, "quiting handlerthread from the endService handler");
                 handlerThread.quit();

            
        ;

    


// end of service

【问题讨论】:

仅使用服务... IntentService 在onHandleIntent 完成后销毁。 你有什么错误吗?如果是,则提供 lagcat @AM 没有错误。它在 onHandleIntent 代码中请求位置更新......然后什么都没有。 @PankajKumar 所以在 gps 找到锁时无法保持 onHandleIntent 存活? android LocationLister implemented in IntentService never execute the OnLocationChanged() method 的可能重复项 【参考方案1】:

正如 Pankaj Kumar 所指出的,IntentService 不适用于要完成的工作本质上是异步的情况。一旦onHandleIntent() 返回,你的服务就会被销毁。

使用常规的Service,在onStartCommand() 中注册位置,使用HandlerThread 处理结果(这样您就可以将其Looper 传递给requestLocationUpdates())。收到您的位置信息或达到合适的超时时间后,请执行您的工作并在服务上调用 stopSelf() 将其关闭。

【讨论】:

您的回复。我已经编辑了问题 [Edit1]。我已按照您的建议将代码改回使用 Service 并覆盖 onStartCommand 。您能否解释和扩展一些有关 handlerThread、looper 和传递到 requestlocationUpdates 的内容。我不太清楚你的意思。谢谢 @turtleboy: developer.android.com/reference/android/location/… 使用带有LooperrequestLocationUpdates() 变体允许您在HandlerThread (developer.android.com/reference/android/os/HandlerThread.html) 上接收LocationListener 回调。这为您提供了工作所需的后台线程。 我再次编辑了帖子 [edit2]。你介意看一下吗,我已经修改了 onStartCommand 方法。我创建了一个 HandlerThread 并启动了它。然后我从 handlerThread 创建了一个 looper 并将它传递给 requestLocationUpdates() ,它接受一个 looper 参数。我还是有点迷失在这里。您之前发送给我的文档说我可以从 looper 获取处理程序,但我不确定从这里做什么以及如何创建您提到的后台线程,我可以将 long 和 lat 传递给网络调用。你介意再详细说明一下吗?谢谢 @turtleboy:“如何创建你提到的后台线程”——你已经创建并启动了HandlerThread。 “我可以将 long 和 lat 传递给网络调用”——在 onLocationChanged() 中。完成网络 I/O 后,您可以通过 quit() HandlerThreadstopSelf() 清理服务,就像 IntentService 在幕后所做的那样。 谢谢,现在可以正常使用了。我已经发布了现在的代码。(edit3)我想我已经按照你的描述做了?我想更多地了解这一切是如何运作的。我之前使用过 requestLocationUpdates() 并从主线程调用它而没有循环。我查了一下Service,它不在自己的线程中运行,所以我认为它在主线程中运行。那么为什么我需要一个活套?您能否简要解释一下这里涉及的机制与主线程、服务、handlerthread、looper 以及它们如何相互交互。感谢您到目前为止的时间。马特

以上是关于位置侦听器从服务而不是 IntentService 工作的主要内容,如果未能解决你的问题,请参考以下文章

Android:如何确定 IntentService 是不是正在运行?

getLastKnownLocation 不是实际位置

停止位置侦听器服务 Android

未从 IntentService 调用 onLocationChanged

在android中使用IntentService从服务器下载文件

多次调用 IntentService 的 startService 时,意图是不是会排队?