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

Posted

技术标签:

【中文标题】在空对象引用上调用虚拟方法“double android.location.Location.getLatitude()”时出错【英文标题】:Error invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference 【发布时间】:2015-11-24 05:40:37 【问题描述】:

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

地点解码器.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();
        
    


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

我做了什么:

    日日夜夜试图解决这个问题。 浏览了许多关于该主题的页面。 尝试了我自己的不同代码。

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

这是我的 LogCat。

Process: com.kkze.Mappy, PID: 6742
java.lang.RuntimeException: Unable to start activity ComponentInfocom.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.access$900(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.access$900(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)

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

【问题讨论】:

所以getLastKnownLocation 正在返回 null,据记录可能会发生这种情况:“如果提供程序当前被禁用,则返回 null。”您的代码应该检查并相应地处理它。您说“在相同条件下” - 是当前禁用位置的条件吗?因为如果是这样,真的没有什么可以解释的了。 我应该怎么做?在相同的条件下,其他应用程序会这样做。或者有没有办法在不获取用户位置的情况下解决我的问题。请帮忙。 很抱歉,如果我向您施加压力或其他什么,但我真的很沮丧,即使在尽我所能搜索 Web 之后,我什至无法解决这么简单的问题。对不起。这边已经半夜了,我还是没办法阻止这个问题的发生。 @Jon Skeet 没有打开任何位置。我的应用程序崩溃。它成功了。如果位置已关闭,我们的两个应用程序都会将用户引导至设置页面以将其打开。 正确,因此 API 的行为完全按照文档说明。在调用任何方法之前,您应该检查 location 是否为 nullif (location == null) /* take appropriate action */ else /* use location */ 【参考方案1】:

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

保证您实际获得位置的唯一方法是请求一个位置,这是通过调用 requestLocationUpdates() 来完成的。

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

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

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

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

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) 
        //.....
    

【讨论】:

感谢您的回答,我会尝试并告诉您。 谢谢。它的工作!太感谢了。它终于奏效了。我还添加了一个加载屏幕,或者更确切地说是Progress Dialog,它现在可以正常工作了。再次感谢丹尼尔。 我以为你说你无法比较 locationnull,这就是这段代码的作用...... @Jon Skeet 我删除了location!=null。 Daniel Nugent 说这并不是真正需要的。它就像一个魅力。这是因为我只是打开位置服务并立即要求它崩溃的位置。需要时间才能找到它。特别是在弱连接上。 Daniel Nugent 的解决方案一直在等待设置位置,然后完成工作。我希望,让它完全防错。还有他对等待屏幕的想法,即我的进度对话框有点填补等待时间,让它运行得有点顺利。无论如何,非常感谢你们的努力,我真的很感激。 @kishore 只是要注意,调用 getLastKnownLocation() 是可选的,但如果你调用它,对结果进行空检查不是可选的! (除非您对应用程序崩溃感到满意!)【参考方案2】:

在您的 getLocation 方法中更改此设置

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

【讨论】:

还要检查位置!=null 需要 ACCESS_FINE_LOCATION 权限,这会弄乱我的应用程序,导致它始终返回为 null。 @KISHORE_ZE:正如我在其他 cmets 中所说的那样,这不是真的。它只是将引用与 null 进行比较——这怎么可能需要更多权限? 获取该位置可能(尽管听起来您无论如何都应该请求该权限)但这与检查它是否为空不同。 但它在问我。如果你愿意,我会给你看logcat。我现在没有PC,但我会在手机中编译它并告诉你。 @Jon Skeet 08-30 01:54:42.735 11831 11831 E SELinux [DEBUG] get_category:变量 seinfo:默认灵敏度:NULL,类别:NULL 08-30 01:54:43.335 11831 11831 E AndroidRuntime 致命异常:主要 08-30 01:54:43.335 11831 11831 E AndroidRuntime 进程:com.mycompany.myapp4,PID:11831 08-30 01:54:43.335 11831 11831 E AndroidRuntime java.lang.RuntimeException:无法启动活动组件信息com.mycompany.myapp4/com.mycompany.myapp4.MainActivity: 可能有一个解决方案,但您似乎确信您无法将引用与 null 进行比较,这对我来说似乎不太可能,所以我不瘦 I 可以进一步帮助您。另外,我要去睡觉了……【参考方案3】:

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

【讨论】:

请注意,此函数返回上一个使用该 API 的应用程序的最后一个已知位置。因此,它不适用于他的设备/模拟器。【参考方案4】:

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

是声明融合的位置

 @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();
    

【讨论】:

您的解决方案不完整。如果 getLastLocation() 返回 null 会发生什么?【参考方案5】:

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

【讨论】:

【参考方案6】:

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

【讨论】:

【参考方案7】:

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

【讨论】:

以上是关于在空对象引用上调用虚拟方法“double android.location.Location.getLatitude()”时出错的主要内容,如果未能解决你的问题,请参考以下文章

尝试在空对象引用上调用虚拟方法 com.google.firebase.iid.FirebaseInstanceId.getInstanceId()'

NullPointerException 错误尝试在空对象引用上调用虚拟方法错误

AsyncTask +数据库尝试在空对象引用上调用虚拟方法[重复]

尝试在空对象引用上调用虚拟方法 'android.view.SurfaceHolder android.view.SurfaceView.getHolder()'

数据库错误:尝试在空对象引用上调用虚拟方法“Cursor .getScene()”[重复]

Android错误尝试在空对象引用上调用虚拟方法[重复]