getLatitude和getLongitude抛出NullPointerException

时间:2017-09-03 11:35:00

标签: java android

美好的一天,

请您解释一下为什么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.

4 个答案:

答案 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)
        }
    }
}