我正在尝试收听位置更改,但有时会调用onLocationChanged
回调,而getLastLocation
会返回null
,而Google地图始终可以正常运行。
注意
如果我重启设备,位置服务只能工作约2天;在此之后,我的应用程序和the SDK example都无法正常运行。
这是我的服务代码:
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"/>
答案 0 :(得分:7)
首先是一个错误。我也遇到了这个问题。
您可以尝试一种简单的解决方法。
在尝试获取最后一个位置之前请求位置更新,即在尝试使用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()
方法。
休息你很高兴。
干杯!
答案 1 :(得分:1)
您正在使用getLastLocation()
用于其他目的之外的目的。当位置感知应用程序第一次启动时使用getLastLocation()
。两天后你应该有一个非常准确的解决方案。你为什么不遵循位置感知设计指南。
我说你需要回归START_STICKY
。但您已对onStartCommand()
和onBind()
进行了编码。您还需要启动该服务,然后绑定到该服务,START_STICKY
在客户端解除绑定后才能工作。
请勿在服务中检查GooglePlay。在启动服务之前,该服务需要在活动中对GooglePlay进行轻量级检查。服务越轻,它就越有可能留在记忆中。在单独的过程中运行Service
。
答案 2 :(得分:1)
我根据以下代码开发了我的应用程序,如果您需要,我可以使用我的应用程序名称是&#34; https://play.google.com/store/apps/details?id=com.deep.profilemaper&#34; 。
这是我的代码: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 {
}
}
}
<强> *** *** Constants.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等常量,仅用于记录目的。所以,我已经排除了该代码。 此代码经过完美测试和运行。试一试。
感谢。
答案 3 :(得分:1)
<强>第一强>
这是旧Android设备上的一种错误。
显然,位置API在不同的Android版本上有不同的行为(LocationManager在Android&gt; = 4.1上有问题,而Play Services在Android 2.3上有问题),请参阅here。
所以我最终得到的是:
尝试通过播放服务检索最后一个位置,如果尝试失败,请尝试使用LocationManager。
<强>第二强>
我想感谢大家提出的宝贵意见,我得到提示,使用AndroidHacker发布的先前解决方法,所以我认为他应该获得赏金。
答案 4 :(得分:1)
如果Google地图尚未确定您设备的位置,则可能会出现此问题。尝试启动Google地图。如果无法在设备的设置中解决此问题(例如启用WLAN + GPS)。
答案 5 :(得分:0)
从the doc开始,很明显有时候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();
}
}
}
答案 6 :(得分:0)
你的服务可能被杀,可能会发生。 尝试将onStartCommand()返回的值更改为
return STICKY_START;
一旦资源可用,这将重新启动服务。
中的相关部分public static final int START_STICKY
在API级别5中添加 从onStartCommand(Intent,int,int)返回的常量:如果此服务的进程在启动时被终止(从onStartCommand(Intent,int,int)返回后),则将其保留在启动状态但不保留此状态交付意图。稍后系统将尝试重新创建服务。因为它处于启动状态,所以它将保证在创建新服务实例后调用onStartCommand(Intent,int,int);如果没有任何挂起的启动命令要传递给服务,它将使用null intent对象调用,因此您必须注意检查这一点。
此模式适用于将在任意时间段内显式启动和停止运行的内容,例如执行背景音乐播放的服务。
常数值:1(0x00000001)
答案 7 :(得分:0)
谷歌地图必须正常工作,因为它必须缓存以前的位置信息或直接使用位置API - 而不是谷歌播放服务位置api ..