2012-07-27 4 views
0

사용자 위치를 얻기 위해 디자인 한 클래스 LocationHelper가 있습니다. 생성시, 필자는 필요한 정확도와 현재 위치가 얼마나되어야 하는지를 지정합니다. 새로 획득 한 위치이거나 최근의 위치가 충분하지 않은 경우 위치 관리자로부터 업데이트를 수신하기를 원합니다. 내 문제는이 방법 중 하나에서 이것이 발생하기를 원하고 정확한 위치가 발견 될 때까지 돌아 오지 않는 것이다. 원하는 위치에 도달 할 때까지 메서드가 반환되지 않게하려면 어떻게합니까? 배경 서비스에서 LocationHelper 클래스 만 사용하므로 반환하는 데 시간이 오래 걸릴 염려가 없습니다. 위치가 null인지 (정확한 위치가 발견 될 때까지) 리턴을 확인하기 전에 while 루프를 넣을 생각을했습니다. 그렇다면 기다림을 실행할 것입니다.하지만 이것을 생각하면 좋습니다. 청취자가 업데이트를받지 못하도록합니까?반환하기 전에 메서드가 정확한 위치를 기다리는 것을 만드는 방법은 무엇입니까?

제 설명이 충분하지 않습니다 (내 문제는 getCurrentFix, 하단에있는 경우), 감사합니다 아래 코드입니다.

package com.s0812532.AutoBagger; 

import java.util.Date; 

import android.content.Context; 
import android.location.Location; 
import android.location.LocationListener; 
import android.location.LocationManager; 
import android.os.Bundle; 
import android.os.Handler; 


/** 
* Class LocationHelper 
* Class for obtaining the user's location. Capable of obtaining the current 
* position, or the most recent fix available fix without getting a new one, in 
* order to conserve battery power. Will automatically decide whether to use 
* GPS/network based on required accuracy. Must not be called directly from the UI 
* thread or the app will become unresponsive. 
*/ 
public class LocationHelper { 

    // 
    // Fields 
    // 

    /** 
    * The maximum accuracy, in metres, for the location fix to be considered accurate enough. 
    */ 
    private int accuracyRequired; 
    /** 
    * The maximum age, in seconds, for the location fix to be considered recent enough. 
    */ 
    private int ageRequired; 
    /** 
    * The Location obtained by the constructor 
    */ 
    private Location position; 
    /** 
    * An instance of the system location manager. 
    */ 
    private LocationManager lm; 
    /** 
    * The context passed in, in order to be able to access system resources like GPS. 
    */ 
    private Context mCtx; 
    /** 
    * The current time, set by the constructor. 
    */ 
    private long time; 
    /** 
    * A scaling factor which is applied to the accuracy of any network 
    * based location fix to compensate for the inaccuracy of its reporting. 
    */ 
    private static final float NETWORK_ACCURACY_SCALE = 5; 

    // 
    // Constructors 
    // 

    /** 
    * Constructor which will get a location fix (current or recent) which meets the 
    * criteria provided so that it can be acted on. 
    * @return 
    * @param  age The maximum age, in seconds, for the location fix to be 
    * considered recent enough. 
    * @param  accuracy The maximum accuracy, in metres, for the location fix to 
    * be considered accurate enough. 
    */ 
    public LocationHelper(Context ctx, int age, int accuracy) 
    { 
     mCtx = ctx; 
     setAgeRequired(age); 
     setAccuracyRequired(accuracy); 
     //Get the time (in milliseconds since UNIX epoch) 
     //TODO - need to test what happens when phone clock is wrong 
     Date now = new Date(); 
     time = now.getTime(); 
     //TODO - handle when LocationManager returns as null 
     lm = (LocationManager) mCtx.getSystemService(Context.LOCATION_SERVICE); 
     //Finally, get a fix to satisfy conditions (if a new fix is required then 
     //getCurrentFix() will detect this and call getCurrentFix() itself. 
     position = getRecentFix(); 
    } 

    // 
    // Methods 
    // 


    // 
    // Accessor methods 
    // 

    /** 
    * Set the value of accuracyRequired 
    * The maximum accuracy, in metres, for the location fix to be considered accurate 
    * enough. 
    * @param newVar the new value of accuracyRequired 
    */ 
    private void setAccuracyRequired (int acc) { 
     //TODO - Test that value is not negative 
     accuracyRequired = acc; 
    } 

    private void setAgeRequired (int age) { 
     //TODO - Test that the value is not negative 
     ageRequired = age; 
    } 


    // 
    // Other methods 
    // 



    /** 
    * Returns the location fix obtained by the constructor. 
    * @return  Location 
    */ 
    public Location getLocation() 
    { 
     return position; 
    } 


    /** 
    * Returns the distance between the user's location and a location provided as an 
    * argument. 
    * @return  float 
    * @param  location 
    */ 
    public float getDistance(Location location) 
    { 
     return position.distanceTo(location); 
    } 


    /** 
    * Obtains the most recent fixes from the GPS and Network location managers, and 
    * stores the more accurate of the two if it is accurate/recent enough, otherwise 
    * it will call getCurrentFix in order to get an accurate enough fix. 
    * @return  Location 
    */ 
    private Location getRecentFix() 
    { 
     //TODO - need to check if location sources are enabled, and deal with it if they aren't 

     Location GPSFix = lm.getLastKnownLocation("GPS"); 
     Location networkFix = lm.getLastKnownLocation("network"); 
     //Adjust the stated accuracy of the network location fix due to errors in reporting 
     networkFix.setAccuracy(networkFix.getAccuracy()/NETWORK_ACCURACY_SCALE); 

     if((GPSFix.getAccuracy() < accuracyRequired) & (time - GPSFix.getTime() < ageRequired)) 
     { 
      //Last GPS fix is good enough, so return it. 
      return GPSFix; 
     } 
     else if ((networkFix.getAccuracy() < accuracyRequired) & (time - networkFix.getTime() < ageRequired)) 
     { 
      //Last network fix is good enough, so return it. 
      return networkFix; 
     } 
     else { 
      //none of the available fixes are good enough, so obtain a new one. 
      return getCurrentFix(); 
     } 
    } 


    /** 
    * Obtains either a GPS or Network based LocationManager, and gets a new fix, if 
    * possible. GPS/Network is decided upon based accuracy required. 
    * @return  Location 
    */ 
    private Location getCurrentFix() 
    { 
     //TODO - need to put in some sort of timeout (perhaps getting status updates will do) 

     LocationListener networkListener = new LocationListener() { 
      public void onLocationChanged(Location loc) { 
       //check to see if new position is accurate enough 
       if (loc.getAccuracy() < accuracyRequired) { 
        position = loc; 
       } 
       else if (new Date().getTime() - time > 15000) { //if it has been looking for network location updates for 15 seconds or more 
        //Get updates from GPS instead 
        lm.requestLocationUpdates("gps", 0, 0, GPSListener); 
       } 
      } 
      public void onProviderDisabled(String provider) { 
       // TODO - network location is/has been disabled by user - do something like warn user it is a bad idea 

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

      } 
     }; 

     LocationListener GPSListener = new LocationListener() { 
      public void onLocationChanged(Location loc) { 
       // TODO - check to see if new position is accurate enough 
       if (loc.getAccuracy() < accuracyRequired) { 
        position = loc; 
       } 
       else if (new Date().getTime() - time > 60000) { //if it has been looking for GPS location updates for 60 seconds or more 
        //TODO Report an error getting location 
       } 
      } 
      public void onProviderDisabled(String provider) { 
       // TODO - GPS is/has been turned off by user - do something like warn user it is a bad idea 

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

      } 
     }; 



     if(accuracyRequired < 200) { 
      //First try network updates, then use GPS if sufficient accuracy not obtained in time 
      lm.requestLocationUpdates("network", 0, 0, networkListener); 
     } 
     else { 
      //GPS updates required for accuracy 
      lm.requestLocationUpdates("gps", 0, 0, GPSListener); 
     } 

     while (position == null){ 
      //Do nothing, this is just to stop the method returning the position until it has been set 
      try { 
       wait(50); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     return position; 
    } 


} 

답변

0

메인 스레드를 차단할 수 있도록 리스너 콜백, 주 스레드에서 만들어진 위치는 (그렇지 않으면 리스너 콜백 happpen하지 않습니다). 서비스가 활동과 동일한 프로세스에서 실행중인 경우 이는 UI 스레드이기도합니다. 이 작업을 수행하려면 LocationHelper이 별도의 스레드에서 실행되고 있는지 확인해야합니다. 그런 다음 while 루프를 추가하여 새 위치에 대한 검사 사이에 잠을 자면됩니다. 앞에서 말했듯이 위치 리스너 콜백은 주 스레드에서 발생하므로 블로킹이 발생하지 않습니다.

이 메시지가 백그라운드 서비스에서 실행된다고 할 때 좀 더 구체적으로 표현할 수 있습니까? 그게 무슨 뜻입니까?

+0

메인 UI와는 다른 스레드에서 실행되며 사용자 상호 작용이 전혀없는 서비스라는 의미입니다. 나는 당신의 대답이 나의 문제를 해결할 것이라고 생각합니다. 감사. – ablack89

+0

차가움. 서비스가 주 스레드에서 실행되는 호출을 가지고 있고 서비스가 활동과 동일한 프로세스 (기본 동작)에서 차단할 수 있다고 판단한 경우에만 해당됩니다. –

관련 문제