播放位置服务getLastLocation返回null
-
21-12-2019 - |
题
我试图听位置变化,但有时 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。.