我试图听位置变化,但有时 onLocationChanged 回调永远不会被调用, getLastLocation 申报表 null, ,而谷歌地图总是工作完美。

如果我重新启动我的设备,位置服务将只工作~2天;在那之后,我的应用程序和 SDK示例 将工作,而谷歌地图仍然工作。

这是我的服务代码:

public class VisitService extends Service implements
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener, 
        LocationListener {

    private final IBinder mBinder = new VisitBinder();


    // A request to connect to Location Services
    private LocationRequest mLocationRequest;

    // Stores the current instantiation of the location client in this object
    private LocationClient mLocationClient;


    private boolean mLocationServiceConnected = false;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        initLocation();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        initLocation();
        return mBinder;
    }

    public void startVisit() {
        if (!servicesConnected()) {
            listener.onVisitStartError();
            return;
        }

        if (mLocationServiceConnected) {
            if (isAcceptableLocation(mLocationClient.getLastLocation())) {
                Toast.makeText(this, "You have arrived!", Toast.LENGTH_LONG);
            } else {
                mVisitListener.onVisitStartError();
            }
        }    
    }

    private boolean isAcceptableLocation(Location location) {
        if (location == null) {
            Toast.makeText(this, "Location is null", Toast.LENGTH_LONG).show();
            return false;
        }

        return true;
    }


    private void initLocation() {

        if (mLocationRequest == null) {
            // Create a new global location parameters object
            mLocationRequest = LocationRequest.create();
            /*
             * Set the update interval
             */
            mLocationRequest
                    .setInterval(LocationUtils.UPDATE_INTERVAL_IN_MILLISECONDS);

            // Use high accuracy
            mLocationRequest
                    .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

            // Set the interval ceiling to one minute
            mLocationRequest
                    .setFastestInterval(LocationUtils.FAST_INTERVAL_CEILING_IN_MILLISECONDS);

        }

        if (mLocationClient == null) {
            mLocationClient = new LocationClient(this, this, this);
            mLocationClient.connect();
        }
    }

    /**
     * Verify that Google Play services is available before making a request.
     * 
     * @return true if Google Play services is available, otherwise false
     */
    private boolean servicesConnected() {

        // Check that Google Play services is available
        int resultCode = GooglePlayServicesUtil
                .isGooglePlayServicesAvailable(this);

        // If Google Play services is available
        if (ConnectionResult.SUCCESS == resultCode) {
            // In debug mode, log the status
            Log.d(LocationUtils.APPTAG,
                    getString(R.string.play_services_available));

            return true;
        } else {

            return false;
        }
    }

    public class VisitBinder extends Binder {
        public VisitService getService() {
            return VisitService.this;
        }
    }


    /**
     * In response to a request to start updates, send a request to Location
     * Services
     */
    private void startPeriodicUpdates() {

        mLocationClient.requestLocationUpdates(mLocationRequest, this);
        Toast.makeText(this, "Location Update Requested", Toast.LENGTH_LONG).show();
    }

    /**
     * In response to a request to stop updates, send a request to Location
     * Services
     */
    private void stopPeriodicUpdates() {
        mLocationClient.removeLocationUpdates(this);

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.d(LocationUtils.APPTAG, "Location Services Connection faild");


    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.d(LocationUtils.APPTAG, "Location Services Connected");
        mLocationServiceConnected = true;
        startPeriodicUpdates();
    }

    @Override
    public void onDisconnected() {
        mLocationServiceConnected = false;
    }

    @Override
    public void onLocationChanged(Location location) {
        Toast.makeText(this, "Location has been changed", Toast.LENGTH_LONG).show();
    }
}

Android清单

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
有帮助吗?

解决方案 3

第一个

这是旧的Android设备上的一种错误。

显然,位置Api在不同的Android版本上有不同的行为(LocationManager在Android>=4.1上有问题,而Play Services在Android2.3上有问题),请参阅 这里.

所以我最终得到的是下面:

尝试通过播放服务检索最后一个位置,如果尝试使用LocationManager失败。

第二

我要感谢你们所有人的宝贵建议,我从AndroidHacker的帖子中得到了使用以前解决方法的提示,所以我认为他是值得赏金的人。

其他提示

首先,它是一个错误。我也面临着这个问题。

你可以尝试一个简单的解决方法。

在尝试获取最后一个位置之前,请执行位置更新请求,即在尝试使用getLastLocation()查找最后一个位置之前,请求位置更新;

就像:

LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria crta = new Criteria();
crta.setAccuracy(Criteria.ACCURACY_FINE);
crta.setAltitudeRequired(true);
crta.setBearingRequired(true);
crta.setCostAllowed(true);
crta.setPowerRequirement(Criteria.POWER_LOW); 
String provider = locationManager.getBestProvider(crta, true);
Log.d("","provider : "+provider);
// String provider = LocationManager.GPS_PROVIDER; 
locationManager.requestLocationUpdates(provider, 1000, 0, locationListener);
Location location = locationManager.getLastKnownLocation(provider); 

此实现基于LocationManager。请选择位置客户端相同.

希望有帮助!

更新资料

在这里,您也可以使用onLocationChanged()方法,因为它会在每次位置更改时更新您,而getLastLocation()方法返回可能为NULL的最佳已知位置。

根据doc,GetLastLocation()方法将在非常罕见的情况下返回NULL。但这种情况也经常发生在我身上。

最新更新

伙计们只有一个关于GPS的更新 :

首先,我们需要利用 GoogleApiClient 相反, LocationClient 类。

其次,我们需要实施 GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener

第三,我们需要复盖它 onConnected() , onConnectionSuspended()onConnectionFailed() 方法。

休息你可以走了。

干杯!

我已经开发了我的应用程序基于下面的代码,你可以使用,如果你想我的应用程序名称是"https://play.google.com/store/apps/details?id=com.deep.profilemaper" .

这是我的代码 :BackgroundLocationService.java语言

public class BackgroundLocationService extends Service implements
    GooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener  {

    IBinder mBinder = new LocalBinder();

    private LocationClient mLocationClient;
    private LocationRequest mLocationRequest;
   // Flag that indicates if a request is underway.
   private boolean mInProgress;

   private Boolean servicesAvailable = false;

public class LocalBinder extends Binder {
    public BackgroundLocationService getServerInstance() {
        return BackgroundLocationService.this;
    }
}

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


    mInProgress = false;
    // Create the LocationRequest object
    mLocationRequest = LocationRequest.create();
    // Use high accuracy
    mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
    // Set the update interval to 5 seconds
    mLocationRequest.setInterval(Constants.UPDATE_INTERVAL);
    // Set the fastest update interval to 1 second
    mLocationRequest.setFastestInterval(Constants.FASTEST_INTERVAL);

    servicesAvailable = servicesConnected();

    /*
     * Create a new location client, using the enclosing class to
     * handle callbacks.
     */
    mLocationClient = new LocationClient(this, this, this);


}

private boolean servicesConnected() {

    // Check that Google Play services is available
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

    // If Google Play services is available
    if (ConnectionResult.SUCCESS == resultCode) {

        return true;
    } else {

        return false;
    }
}

public int onStartCommand (Intent intent, int flags, int startId)
{
    super.onStartCommand(intent, flags, startId);

    if(!servicesAvailable || mLocationClient.isConnected() || mInProgress)
        return START_STICKY;

    setUpLocationClientIfNeeded();
    if(!mLocationClient.isConnected() || !mLocationClient.isConnecting() && !mInProgress)
    {
        appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE);
        mInProgress = true;
        mLocationClient.connect();
    }

    return START_STICKY;
}

/*
 * Create a new location client, using the enclosing class to
 * handle callbacks.
 */
private void setUpLocationClientIfNeeded()
{
    if(mLocationClient == null) 
        mLocationClient = new LocationClient(this, this, this);
}

// Define the callback method that receives location updates
@Override
public void onLocationChanged(Location location) {
    // Report to the UI that the location was updated
    String msg = Double.toString(location.getLatitude()) + "," +
            Double.toString(location.getLongitude());
    Log.d("debug", msg);
    // Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    appendLog(msg, Constants.LOCATION_FILE);
}

@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

public String getTime() {
    SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return mDateFormat.format(new Date());
}

public void appendLog(String text, String filename)
{       
   File logFile = new File(filename);
   if (!logFile.exists())
   {
      try
      {
         logFile.createNewFile();
      } 
      catch (IOException e)
      {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }
   try
   {
      //BufferedWriter for performance, true to set append to file flag
      BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); 
      buf.append(text);
      buf.newLine();
      buf.close();
   }
   catch (IOException e)
   {
      // TODO Auto-generated catch block
      e.printStackTrace();
   }
}

@Override
public void onDestroy(){
    // Turn off the request flag
    mInProgress = false;
    if(servicesAvailable && mLocationClient != null) {
        mLocationClient.removeLocationUpdates(this);
        // Destroy the current location client
        mLocationClient = null;
    }
    // Display the connection status
    // Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
    appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Stopped", Constants.LOG_FILE);
    super.onDestroy();  
}

/*
 * Called by Location Services when the request to connect the
 * client finishes successfully. At this point, you can
 * request the current location or start periodic updates
 */
@Override
public void onConnected(Bundle bundle) {

    // Request location updates using static settings
    mLocationClient.requestLocationUpdates(mLocationRequest, this);
    appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Connected", Constants.LOG_FILE);

}

/*
 * Called by Location Services if the connection to the
 * location client drops because of an error.
 */
@Override
public void onDisconnected() {
    // Turn off the request flag
    mInProgress = false;
    // Destroy the current location client
    mLocationClient = null;
    // Display the connection status
    // Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
    appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected", Constants.LOG_FILE);
}

/*
 * Called by Location Services if the attempt to
 * Location Services fails.
 */
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    mInProgress = false;

    /*
     * Google Play services can resolve some errors it detects.
     * If the error has a resolution, try sending an Intent to
     * start a Google Play services activity that can resolve
     * error.
     */
    if (connectionResult.hasResolution()) {

    // If no resolution is available, display an error dialog
    } else {

      }
    }

}

***常量。java语言***

public final class Constants {

// Milliseconds per second
private static final int MILLISECONDS_PER_SECOND = 1000;
// Update frequency in seconds
private static final int UPDATE_INTERVAL_IN_SECONDS = 30;
// Update frequency in milliseconds
public static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
// The fastest update frequency, in seconds
private static final int FASTEST_INTERVAL_IN_SECONDS = 30;
// A fast frequency ceiling in milliseconds
public static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
// Stores the lat / long pairs in a text file
public static final String LOCATION_FILE = "sdcard/location.txt";
// Stores the connect / disconnect data in a text file
public static final String LOG_FILE = "sdcard/log.txt";


/**
 * Suppress default constructor for noninstantiability
 */
private Constants() {
    throw new AssertionError();
    }
}

此代码包含一些变量,如当前日期和时间以及仅用于日志记录目的的常量,如LOG_File。所以,我已经排除了该代码。这个代码是完美的测试和工作。试一试。

谢谢.

如果google地图尚未确定设备的位置,则可能会出现此问题。尝试启动谷歌地图。如果它不能在设备的设置中解决这个问题(比如通过启用WLAN+GPS)。

您正在使用 getLastLocation() 目的不是为了它的目的。 getLastLocation() 当位置感知应用程序是第一次启动时使用。两天后,你应该有一个非常准确的修复。为什么你没有遵循位置感知设计指南。

我想你得回来 START_STICKY.但你已经编码了 onStartCommand()onBind().您还需要启动该服务,然后将其绑定到 START_STICKY 在客户解除绑定后工作。

不要在服务中检查GooglePlay。在启动服务之前,该服务需要在活动中对GooglePlay进行轻量级检查。服务越轻,它留在内存中的机会就越大。运行 Service 在单独的过程中。

医生, ,很明显,有时可能 getLastLocation() 返回null。所以,取决于你的意思是"我无法接收onLocationChanged回调",你可以推迟你的 startVisit 重要的调用(您的吐司现在显示),直到您收到这个onLocationChanged回调。这样,如果您可以直接访问最后一个已知位置,这将是直接的,否则您将等待onLocationChanged回调

public class VisitService extends Service implements
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener, 
        LocationListener {
    //...
    boolean mIsInitialized=false;
    Location mCurrentLocation;
    boolean mStartVisitsCalled=false;
    //...

    public void startVisit() {
        if (!servicesConnected()) {
            listener.onVisitStartError();
            return;
        }

        if (mLocationServiceConnected) {
        if (((mLocationClient.getLastLocation() != null && isAcceptableLocation(mLocationClient.getLastLocation()))
                || (isInitialized && isAcceptableLocation(mCurrentLocation))) {
                //doNiceStuff();
            } else
                mStartVisitsCalled=true;
                //Wait...
            }
        }    
    }
    //...

    @Override
    public void onLocationChanged(Location location) {
        this.mIsInitialized=true;
        this.mCurrrentLocation = location;
        if(mStartVisitsCalled) {
            //delayed doNiceStuff();
        }

    }
}

它可能是你的服务只是被杀死,它可能发生。尝试将onStartCommand()返回的值更改为

return STICKY_START;

这将在资源可用时立即重新启动服务。

以下是 空气污染指数参考

公共静态最终int START_STICKY

在API级别5中添加 常量从onStartCommand返回(Intent,int,int):如果此服务的进程在启动时被杀死(从onStartCommand(Intent,int,int)返回后),则将其保留为started状态,但不保留此delivered intent。稍后系统将尝试重新创建服务。因为它处于started状态,所以它将保证在创建新的服务实例后调用onStartCommand(Intent,int,int);如果没有任何挂起的启动命令要传递到服务,它将使用null intent对象调用,因此您必须注意检查这一点。

这种模式对于将显式启动和停止运行任意时间段的事物是有意义的,例如执行背景音乐播放的服务。

常数值:1(0x00000001)

谷歌地图必须工作,因为它必须缓存以前的位置信息或直接使用位置api-而不是谷歌播放服务位置api。.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top