Java 在空对象引用上调用虚拟方法“double android.location.Location.getLatitude()”时出错

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32290045/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:18:23  来源:igfitidea点击:

Error invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference

javaandroidgoogle-mapsnullpointerexceptionlocation

提问by KISHORE_ZE

All I am trying to do is let the user get a list of the places of types he likes. For example if the input was hospital my application would open google maps with the search string "Hospital". But as suggested in the documentation using the geocode like geo:0,0?q=hospitaluri shows all the hospitals near the coordinates 0 latitude & 0 longitude. So when I tried to get the users coordinates first by using the following code.

我想要做的就是让用户获得他喜欢的类型地​​点的列表。例如,如果输入是医院,我的应用程序将使用搜索字符串“医院”打开谷歌地图。但正如使用地理编码的文档中所建议的geo:0,0?q=hospitaluri 显示坐标 0 纬度和 0 经度附近的所有医院。因此,当我尝试使用以下代码首先获取用户坐标时。

Places Decoder.java

位置解码器.java

package com.kkze.Mappy;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

public class PlacesDecoder extends Activity {
Intent intentThatCalled;
public double latitude;
public double longitude;
public LocationManager locationManager;
public Criteria criteria;
public String bestProvider;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    intentThatCalled = getIntent();
    String voice2text = intentThatCalled.getStringExtra("v2txt");
    getLocation(voice2text);
}
public static boolean isLocationEnabled(Context context)
{
    int locationMode = 0;
    String locationProviders;
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
    {
        try
        {
            locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
        } catch (Settings.SettingNotFoundException e) {
            e.printStackTrace();
        }
        return locationMode != Settings.Secure.LOCATION_MODE_OFF;
    }
    else
    {
        locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
        return !TextUtils.isEmpty(locationProviders);
    }
}

public void getLocation(String voice2txt) {
    locationManager = (LocationManager)  this.getSystemService(Context.LOCATION_SERVICE);
    criteria = new Criteria();
    bestProvider = String.valueOf(locationManager.getBestProvider(criteria, true)).toString();
    Location location = locationManager.getLastKnownLocation(bestProvider);
    if (isLocationEnabled(PlacesDecoder.this)) {
            Log.e("TAG", "GPS is on");
            latitude = location.getLatitude();
            longitude = location.getLongitude();
            Toast.makeText(PlacesDecoder.this, "latitude:" + latitude + " longitude:" + longitude, Toast.LENGTH_SHORT).show();
            searchNearestPlace(voice2txt);

        }
    else
    {
        AlertDialog.Builder notifyLocationServices = new AlertDialog.Builder(PlacesDecoder.this);
        notifyLocationServices.setTitle("Switch on Location Services");
        notifyLocationServices.setMessage("Location Services must be turned on to complete this action. Also please take note that if on a very weak network connection,  such as 'E' Mobile Data or 'Very weak Wifi-Connections' it may take even 15 mins to load. If on a very weak network connection as stated above, location returned to application may be null or nothing and cause the application to crash.");
        notifyLocationServices.setPositiveButton("Ok, Open Settings", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Intent openLocationSettings = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                PlacesDecoder.this.startActivity(openLocationSettings);
                finish();
            }
        });
        notifyLocationServices.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                finish();
            }
        });
        notifyLocationServices.show();
    }
}

public void searchNearestPlace(String v2txt) {
    Log.e("TAG", "Started");
    v2txt = v2txt.toLowerCase();
    String[] placesS = {"accounting", "airport", "aquarium", "atm", "attraction", "bakery", "bakeries", "bank", "bar", "cafe", "campground", "casino", "cemetery", "cemeteries", "church", "courthouse", "dentist", "doctor", "electrician", "embassy", "embassies", "establishment", "finance", "florist", "food", "grocery", "groceries", "supermarket", "gym", "health", "hospital", "laundry", "laundries", "lawyer", "library", "libraries", "locksmith", "lodging", "mosque", "museum", "painter", "park", "parking", "pharmacy", "pharmacies", "physiotherapist", "plumber", "police", "restaurant", "school", "spa", "stadium", "storage", "store", "synagog", "synagogue", "university", "universities", "zoo"};
    String[] placesM = {"amusement park", "animal care", "animal care", "animal hospital", "art gallery", "art galleries", "beauty salon", "bicycle store", "book store", "bowling alley", "bus station", "car dealer", "car rental", "car repair", "car wash", "city hall", "clothing store", "convenience store", "department store", "electronics store", "electronic store", "fire station", "funeral home", "furniture store", "gas station", "general contractor", "hair care", "hardware store", "hindu temple", "home good store", "homes good store", "home goods store", "homes goods store", "insurance agency", "insurance agencies", "jewelry store", "liquor store", "local government office", "meal delivery", "meal deliveries", "meal takeaway", "movie rental", "movie theater", "moving company", "moving companies", "night club", "pet store", "place of worship", "places of worship", "post office", "real estate agency", "real estate agencies", "roofing contractor", "rv park", "shoe store", "shopping mall", "subway station", "taxi stand", "train station", "travel agency", "travel agencies", "veterinary care"};
    int index;
    for (int i = 0; i <= placesM.length - 1; i++) {
        Log.e("TAG", "forM");
        if (v2txt.contains(placesM[i])) {
            Log.e("TAG", "sensedM?!");
            index = i;
            Uri gmmIntentUri = Uri.parse("geo:" + latitude + "," + longitude + "?q=" + placesM[index]);
            Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
            mapIntent.setPackage("com.google.android.apps.maps");
            startActivity(mapIntent);
            finish();
        }
    }
    for (int i = 0; i <= placesS.length - 1; i++) {
        Log.e("TAG", "forS");
        if (v2txt.contains(placesS[i])) {
            Log.e("TAG", "sensedS?!");
            index = i;
            Uri gmmIntentUri = Uri.parse("geo:" + latitude + "," + longitude + "?q=" + placesS[index]);
            Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
            mapIntent.setPackage("com.google.android.apps.maps");
            startActivity(mapIntent);
            finish();
        }
    }
}
}

The problem is that always and always location returns null. And I know for a fact that another application Jarvis easily does the task as long as location is enabled, if not is simply asks the user to. But under the same conditions my application always crashes.

问题是始终和始终位置返回空值。而且我知道一个事实,只要启用了位置,另一个应用程序 Jarvis 就可以轻松完成任务,否则只是要求用户这样做。但在相同条件下,我的应用程序总是崩溃。

What I have done:

我做了什么:

  1. Spent Day and Night trying to solve this problem.
  2. Browsed through numerous pages on the topic.
  3. Tried different codes of my own.
  1. 花了一天一夜的时间试图解决这个问题。
  2. 浏览了有关该主题的许多页面。
  3. 尝试了我自己的不同代码。

And it still happens. I am a beginner in Android. And please, please do help me. Is there no possible way to solve my problem? even thought that other application somehow manages to do it.

它仍然发生。我是 Android 的初学者。拜托,请帮帮我。没有办法解决我的问题吗?甚至认为其他应用程序以某种方式设法做到了。

This my LogCat.

这是我的 LogCat。

Process: com.kkze.Mappy, PID: 6742
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.kkze.Mappy/com.kkze.Mappy.PlacesDecoder}: java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2658)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2723)
        at android.app.ActivityThread.access0(ActivityThread.java:172)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1422)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:145)
        at android.app.ActivityThread.main(ActivityThread.java:5832)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference
        at com.kkze.Mappy.PlacesDecoder.getLocation(PlacesDecoder.java:62)
        at com.kkze.Mappy.PlacesDecoder.onCreate(PlacesDecoder.java:32)
        at android.app.Activity.performCreate(Activity.java:6221)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2611)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2723)
at android.app.ActivityThread.access0(ActivityThread.java:172)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1422)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5832)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)

Also checking for location!=null requires ACCESS_FINE_LOCATION permission which messes up my app causing it to always return as null.

还要检查 location!=null 需要 ACCESS_FINE_LOCATION 权限,这会弄乱我的应用程序,导致它始终返回为 null。

采纳答案by Daniel Nugent

As Jon Skeet mentioned in the comments, the getLastKnownLocation()method can and will return null. The main problem is that it doesn't prompt a request to the OS for a new location lock, instead it just checks if there was a last known location from some other app's location request. If no other app had recently made a location request, then you get a null location returned to you.

正如 Jon Skeet 在评论中提到的,该getLastKnownLocation()方法可以并且将返回 null。主要问题是它不会向操作系统提示新的位置锁定请求,而只是检查是否存在来自其他应用程序的位置请求的最后一个已知位置。如果最近没有其他应用发出位置请求,那么您会得到一个空位置返回给您。

The only way to guarantee that you actually get a location is to request one, and this is done with a call to requestLocationUpdates().

确保您实际获得位置的唯一方法是请求一个位置,这是通过调用requestLocationUpdates().

The location passed into the onLocationChanged()callback method will not be null, since the callback only occurs on a successful location lock.

传递给onLocationChanged()回调方法的位置不会为空,因为回调只发生在成功的位置锁定上。

Just to note, the entire time your app is registered for location updates, it will be causing extra battery drain, so be sure to un-register for location updates as soon as possible. Here it looks like you can un-register as soon as the first location comes in.

请注意,在您的应用注册位置更新的整个过程中,这将导致额外的电池消耗,因此请务必尽快取消注册位置更新。在这里,您似乎可以在第一个位置进入后立即取消注册。

Also, you might want to consider showing a progress dialog in this Activity while it waits for a location lock in order to give the user some feedback that the app is waiting on something.

此外,您可能需要考虑在此 Activity 等待位置锁定时显示进度对话框,以便向用户提供应用程序正在等待某些内容的反馈。

Here is the general structure of what your code should look like:

以下是您的代码的一般结构:

public class MainActivity extends Activity
        implements LocationListener {

    Intent intentThatCalled;
    public double latitude;
    public double longitude;
    public LocationManager locationManager;
    public Criteria criteria;
    public String bestProvider;

    String voice2text; //added

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        intentThatCalled = getIntent();
        voice2text = intentThatCalled.getStringExtra("v2txt");
        getLocation();
    }

    public static boolean isLocationEnabled(Context context)
    {
       //...............
        return true;
    }

    protected void getLocation() {
        if (isLocationEnabled(MainActivity.this)) {
            locationManager = (LocationManager)  this.getSystemService(Context.LOCATION_SERVICE);
            criteria = new Criteria();
            bestProvider = String.valueOf(locationManager.getBestProvider(criteria, true)).toString();

            //You can still do this if you like, you might get lucky:
            Location location = locationManager.getLastKnownLocation(bestProvider);
            if (location != null) {
                Log.e("TAG", "GPS is on");
                latitude = location.getLatitude();
                longitude = location.getLongitude();
                Toast.makeText(MainActivity.this, "latitude:" + latitude + " longitude:" + longitude, Toast.LENGTH_SHORT).show();
                searchNearestPlace(voice2text);
            }
            else{
                //This is what you need:
                locationManager.requestLocationUpdates(bestProvider, 1000, 0, this);
            }
        }
        else
        {
            //prompt user to enable location....
            //.................
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        locationManager.removeUpdates(this);

    }

    @Override
    public void onLocationChanged(Location location) {
        //Hey, a non null location! Sweet!

        //remove location callback:
        locationManager.removeUpdates(this);

        //open the map:
        latitude = location.getLatitude();
        longitude = location.getLongitude();
        Toast.makeText(MainActivity.this, "latitude:" + latitude + " longitude:" + longitude, Toast.LENGTH_SHORT).show();
        searchNearestPlace(voice2text);
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    public void searchNearestPlace(String v2txt) {
        //.....
    }
}

回答by Stas Parshin

Change this in your getLocationmethod

在你的getLocation方法中改变这一点

if (isLocationEnabled(PlacesDecoder.this) && location != null) {
 ...
}

回答by Yash Patel

Null pointer exception occurs because your app doesn't request for the current location it rather it uses last found location and just checks you've turned your location on and run any other app which uses your current location. After that just try to run your project again. Hope this solves your problem.

发生空指针异常是因为您的应用程序不会请求当前位置,而是使用上次找到的位置,只是检查您是否已打开位置并运行使用您当前位置的任何其他应用程序。之后,只需尝试再次运行您的项目。希望这能解决您的问题。

回答by Mosayeb Masoumi

you wrote codes that get your current location (latlng) and this error is because of your gps(location) on your real android device is not turn on. I turned it on and it works for me. hope to be useful

您编写了获取当前位置 (latlng) 的代码,而此错误是因为您的真实 android 设备上的 gps(location) 未打开。我打开它,它对我有用。希望有用

回答by Qasim

here is another way to do this one your fuse location concept i have used this and was successfull to me mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

这是另一种方法来做到这一点你的保险丝位置概念我已经使用了这个并且对我来说是成功的 mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

is declaration fused location

是声明融合位置

 @SuppressWarnings( {"MissingPermission"})
private void enableLocationComponent() {
    System.out.println("on map click is here in permission///////////////");
    // Check if permissions are enabled and if not request
    if (PermissionsManager.areLocationPermissionsGranted(this)) {

        // Activate the MapboxMap LocationComponent to show user location
        // Adding in LocationComponentOptions is also an optional parameter
        LocationComponent locationComponent = mapboxMap.getLocationComponent();
        locationComponent.activateLocationComponent(this);
        locationComponent.setLocationComponentEnabled(true);
        // Set the component's camera mode
        locationComponent.setCameraMode(CameraMode.TRACKING);

        mFusedLocationClient.getLastLocation().addOnSuccessListener(this, new OnSuccessListener<Location>() {
                    @Override
                    public void onSuccess(Location location) {
                        originLocation=location;
                        // Got last known location. In some rare situations this can be null.
                        if (location != null) {
                            originLocation=location;
                            System.out.println(" permission granted location is in iff ++///////////////"+location);
                        }
                    }
                });

        //originLocation = locationComponent.getLastKnownLocation();
        System.out.println("origin location is that//////////"+originLocation);


    } else {


        permissionsManager = new PermissionsManager(this);
        permissionsManager.requestLocationPermissions(this);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
    Toast.makeText(this, "granted", Toast.LENGTH_LONG).show();
}

@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
    Toast.makeText(this, R.string.user_location_permission_explanation, Toast.LENGTH_LONG).show();
}

@Override
public void onPermissionResult(boolean granted) {
    if (granted) {
        enableLocationComponent();
    } else {
        Toast.makeText(this, R.string.user_location_permission_not_granted, Toast.LENGTH_LONG).show();``
        finish();
    }
}

回答by manojkragy

As Said by Yash your App does not request for the current Location rather it uses last found location a simple work around that worked for me for this Error is that, Switch On your GPS and open your google maps app on your mobile or emulator see your current Location and then close it. Now , when your open your Current App (You working on) or run it ,it would not give this error. worked for me.

正如 Yash 所说,您的应用程序不会请求当前位置,而是使用上次找到的位置,一个对我有用的简单解决方法是,打开您的 GPS 并在您的手机或模拟器上打开您的谷歌地图应用程序,查看您的当前位置,然后关闭它。现在,当您打开当前应用程序(您正在处理)或运行它时,它不会出现此错误。为我工作。

回答by MalyckUsman

I got the same problem using .getLastLocation(). Then I used mMap.setMyLocationEnabeled(true), and got the GPS location using the on map location button enabled by the .setMyLocationEnabeled(true). After that the next time .getLastLocation()worked fine. I don't know the exact reason but I think the on map location button once saved my current location and the next time I used .getLastLocation(), it was not null because the last location was already there.

我在使用时遇到了同样的问题.getLastLocation()。然后我使用mMap.setMyLocationEnabeled(true),并使用由.setMyLocationEnabeled(true). 之后,下一次.getLastLocation()工作正常。我不知道确切的原因,但我认为地图上的位置按钮曾经保存了我当前的位置,下次我使用时.getLastLocation(),它不为空,因为最后一个位置已经存在。