Search code examples
androidgoogle-mapsandroid-recyclerviewgeolocation

Getting Latitude and Longitude?


I am trying to get Location on Button Click in my RecyclerView.

But When I click on the button the application crashes giving me this error

Logcat :

java.lang.NullPointerException: Attempt to invoke virtual method 'android.location.Location android.location.LocationManager.getLastKnownLocation(java.lang.String)' on a null object reference

RecyclerView Adapter Code :

public class RecieverAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable {
Context context;
List<BloodData> data = Collections.emptyList();
List<BloodData> searchData;
LayoutInflater inflater;
RecieverAdapter RAdapter;
LocationManager locationManager;
public RecieverAdapter(RecieveBlood recieveBlood, List<BloodData> data) {
    this.context = recieveBlood;
    inflater = LayoutInflater.from( context );
    this.data = data;
    this.RAdapter = this;
    searchData = new ArrayList<>( data );
}

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
    View view = inflater.inflate( R.layout.blood_list, viewGroup, false );
    MyHolder holder = new MyHolder(view);
    return holder;
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
    MyHolder myHolder = (MyHolder) viewHolder;
    BloodData current = data.get( i );
    myHolder.Sr_Num.setText( " "+i );
    myHolder.Donar_Name.setText( "Name : "+current.getD_Name() );
    myHolder.Donar_Blood_Group.setText( "Blood Group : " +current.getD_blood_group());
    myHolder.Donar_Mobile.setText( "Mobile : "+current.getD_Number());
    myHolder.Donar_Gender.setText( "Gender : "+current.getD_Gender());

    myHolder.location1.setOnClickListener( new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            getLocation();
        }
    } );

}

void getLocation() {
    if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

        ActivityCompat.requestPermissions( (Activity) context, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 101);

    }else{
        Location location = locationManager.getLastKnownLocation( LocationManager.NETWORK_PROVIDER );

        if(location != null){
            double lati = location.getLatitude();
            double longi = location.getLongitude();

            Log.e(TAG,"Location :" +lati+ " ,"+longi );
        }
    }
}



@Override
public int getItemCount() {
    return data.size();
}
 private class MyHolder extends  RecyclerView.ViewHolder{
    TextView Sr_Num,Donar_Name,Donar_Blood_Group,Donar_Mobile,Donar_Gender;
    Button location1, location2;
    public MyHolder(@NonNull View itemView) {
        super( itemView );

        Sr_Num = (TextView) itemView.findViewById( R.id.sr_number );
        Donar_Name = (TextView) itemView.findViewById( R.id.Donar_Name );
        Donar_Blood_Group  =(TextView) itemView.findViewById( R.id.Donar_blood_Group);
        Donar_Mobile = (TextView) itemView.findViewById( R.id.Donar_Number );
        Donar_Gender = (TextView) itemView.findViewById( R.id.Donar_Gender );
        location1 = (Button) itemView.findViewById( R.id.Location1 );
        location2 = (Button) itemView.findViewById( R.id.location2 );


    }
}
}

I set all permission that is required for the location.

Android MainFest File :

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="nikhil.bloodbank.bloodsupplies">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

So whenever I click on the Button the app crashes give me that error. And I have also checked manually whether the permission is given or not.


Solution

  • You haven't initialized your location manager instance. change your adapters constructor as below:

    public RecieverAdapter(RecieveBlood recieveBlood, List<BloodData> data) {
        this.context = recieveBlood;
        inflater = LayoutInflater.from( context );
        this.data = data;
        this.RAdapter = this;
        searchData = new ArrayList<>( data );
    
        //Initialize Location manager
        locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
    }
    

    And be informed that using getLastKnownLocation() may return an old and out of date location, as explained in android docs:

    Returns a Location indicating the data from the last known location fix obtained from the given provider.

    This can be done without starting the provider. Note that this location could be out-of-date, for example, if the device was turned off and moved to another location.

    If the provider is currently disabled, null is returned.

    There are great explanations around multiple ways of getting the location in the link below: https://developer.android.com/guide/topics/location/strategies

    UPDATE

    I've added the locationListener logic below, but best practice is to place you're location fetching code in your activity or fragment, keep in mind that locationListener should be removed when activity or fragment is closed. use locationManager.removeUpdates(locationListener) in order to remove locationListener.

    void getLocation() {
        if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions( (Activity) context, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, 101);
        }else{
            Location location = locationManager.getLastKnownLocation( LocationManager.NETWORK_PROVIDER );
            if(location != null){
                double lati = location.getLatitude();
                double longi = location.getLongitude();
                Log.e(TAG,"Location :" +lati+ " ,"+longi );
            } else {
                boolean isNetworkAvailable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
                if(isNetworkAvailable) fetchCurrentLocation()
                else //Redirect user to device settings in order to turn on location service
            }
        }
    }
    

    You should implement the locationListener as below:

    fetchCurrentLocation() {
            try {
                    LocationListener locationListener = new LocationListener() {
                        @Override
                        public void onLocationChanged(final Location location) {
                            if (location != null) {
                                locationManager.removeUpdates(this);
                                double lati = location.getLatitude();
                                double longi = location.getLongitude();
                                Log.e(TAG,"Location :" +lati+ " ,"+longi );
                            }
                        }
    
                        @Override
                        public void onProviderDisabled(String s) {
                            locationManager.removeUpdates(this);
                        }
    
                        @Override
                        public void onStatusChanged(String s, int i, Bundle bundle) {
                        }
    
                        @Override
                        public void onProviderEnabled(String s) {
                        }
                    };
    
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 500L,30f, locationListener);
                } catch (SecurityException e) {
                    e.printStackTrace();
                }
    }