美好的一天,
请您解释一下为什么getLongitude和getLatitude返回nullPointerException?
事实是问题已经解决了,但有一件事让我烦恼,因为我们的论文协调员可能会问这个问题。情况是我必须得到用户的当前坐标(经度和纬度)。我决定使用FusedLocationClient.getLastLocation()来获取坐标。
mFusedLocationClient = getFusedLocationProviderClient(this);
//app already crashes once the line below is executed
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
if(location != null){
//myLocation is an instance variable of this class
myLocation = location;
}else{
Toast.makeText(PlaceCategoriesActivity.this, "Location fetch failed!", Toast.LENGTH_SHORT).show();
}
}
});
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
应用程序似乎编译正常,但随后崩溃,通过在myLocation.getLatiude()和myLocation.getLongititude()上添加调试断点进行检查,结果发现此方法调用空指针异常,这对我来说很奇怪,因为myLocation已经引用了addOnSuccessListener的onSuccess方法带来的位置对象。
我已经通过移动最后两行代码并将其放入监听器中解决了这个问题:
mFusedLocationClient = getFusedLocationProviderClient(this);
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
if(location != null){
myLocation = location;
//moved the 2 lines of code and it now works
latitude = myLocation.getLatitude();
longitude = myLocation.getLongitude();
}else{
Toast.makeText(PlaceCategoriesActivity.this, "Location fetch failed!", Toast.LENGTH_SHORT).show();
}
}
});
//Toast returns a value of 0 on latitude and 0 on longitude
Toast.makeText(this, "Lat: " + latitude + "Long: + " + longitude, Toast.LENGTH_SHORT).show();
有趣的是,经度和纬度显示在Toast上,两者的值均为0.
答案 0 :(得分:3)
对我来说很奇怪,因为myLocation已经引用了addOnSuccessListener的onSuccess方法带来的位置对象
让我们简化您的第一个代码清单:
mFusedLocationClient = getFusedLocationProviderClient(this);
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
此处,myLocation
尚未分配值。如果您尚未在前一行中为myLocation
分配值,则myLocation
将为null
,您将获得NullPointerException
。
现在,让我们将一些行恢复到该代码段:
mFusedLocationClient = getFusedLocationProviderClient(this);
//app already crashes once the line below is executed
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
}
});
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
addOnSuccessListener()
中的最后一个词是“听众”。这表明您正在注册事件监听器。通常 - 尽管不总是 - 这样的监听器仅在未来事件上被调用。有可能onSuccess()
直到稍后才被调用。但是,您的程序会继续运行,然后您尝试在getLatitude()
上调用myLocation
。由于我们仍未执行任何操作来为myLocation
分配值,因此它将为null
,您将使用NullPointerException
崩溃。
因此,虽然您的第一个代码段确实为myLocation
分配了一个值,但作为程序员,您必须假设在将来某个时间之前它不会这样做(例如,当我们获得新的位置修复时)。在myLocation
为其分配值之前,请勿尝试使用onSuccess()
。
答案 1 :(得分:1)
您不应在addOnSuccessListener
之后添加这些行:
latitude = myLocation.getLatitude(); //this line throws NullPointerException
longitude = myLocation.getLongitude();
因为您必须等到mFusedLocationClient
成功获得LastLocation
即将这些行移至onSuccess
方法!
至于nullPointerException
的原因是因为myLocation
尚未初始化!
答案 2 :(得分:1)
您只需在获得位置时显示位置,而不是之前。那就是说,只需将显示代码放在监听器中即可。
mFusedLocationClient = getFusedLocationProviderClient(this);
// Register a listener, that will be called when the location will be available
mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
if (location != null) {
// We have a location!
myLocation = location;
// So print it now
latitude = myLocation.getLatitude();
longitude = myLocation.getLongitude();
Toast.makeText(PlaceCategoriesActivity.this, "Lat: " + latitude + "Long: + " + longitude, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(PlaceCategoriesActivity.this, "Location fetch failed!", Toast.LENGTH_SHORT).show();
}
}
});
// Loading, as we wait for listener to be called
Toast.makeText(this, "Loading...", Toast.LENGTH_SHORT).show();
答案 3 :(得分:1)
示例:
class LocationApi : Service(), GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private var myGoogleApiClient: GoogleApiClient? = null
private val myLocationRequest = LocationRequest.create()
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
myGoogleApiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.build()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
myGoogleApiClient?.connect()
return super.onStartCommand(intent, flags, startId)
}
override fun onDestroy() {
myGoogleApiClient?.disconnect()
if (myGoogleApiClient != null && myGoogleApiClient?.isConnected!!) {
LocationServices.getFusedLocationProviderClient(this).removeLocationUpdates(locationCallBack)
}
super.onDestroy()
}
override fun onConnected(bundle: Bundle?) {
//here u can define your interval and priority
// request locations, check permissions ok
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationServices.getFusedLocationProviderClient(this).requestLocationUpdates(myLocationRequest, locationCallBack, Looper.myLooper())
}
}
override fun onConnectionSuspended(p0: Int) {
}
override fun onConnectionFailed(p0: ConnectionResult) {
}
override fun onLocationChanged(location: Location?) {
//saving location on DB
LocationInteractor(location)
}
private val locationCallBack = object : LocationCallback() {
override fun onLocationResult(location: LocationResult) {
super.onLocationResult(location)
onLocationChanged(location.lastLocation)
}
}
}