0

I have a fragment where I want to get my current coordinates and then use Retrofit to make a request to Zomato Api but my current location is returning null. I tried to delete the code relative to my api call and the app return my correct latitude and longitude. What am I doing wrong?Below is my Java class.

My Fragment

public class RestaurantsList extends Fragment {
    private RestaurantAdapter mAdapter;
    private RecyclerView mRecyclerView;
    protected static List<Restaurant_> restaurantsList;
    private Context context;
    protected static OnRestaurantClickedListener listener;
    private FirebaseAuth mAuth;
    private static final int REQUEST_FINE_LOCATION=100;
    private LocationRequest mLocationRequest;
    private LocationCallback mLocationCallback;
    private FusedLocationProviderClient mFusedLocationClient;
    private Location myLocation;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = getContext();
        mAuth = FirebaseAuth.getInstance();
        restaurantsList= new ArrayList<>(50);
        getLastLocation();
        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());


        mFusedLocationClient.getLastLocation().addOnSuccessListener(getActivity(), new OnSuccessListener<Location>() {
            @Override
            public void onSuccess(Location location) {
                if (location != null) {
                    myLocation=location;
                    Toast.makeText( getActivity(),"Latitude: "+location.getLatitude()+" Longitude: "+location.getLongitude(), Toast.LENGTH_SHORT).show();

                }
            }
        }).addOnFailureListener(getActivity(), new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Toast.makeText( getActivity(),"It wasn´t possible to determine your location", Toast.LENGTH_SHORT).show();
            }
        });

        getApi().getNearbyRestaurants(myLocation.getLatitude(),myLocation.getLongitude(),20,10000,"rating","desc","75be9f9e2239fe637bf9cb1b46979d91")
                .enqueue(new Callback<ApiResponse>() {
                    @Override
                    public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
                        List<Restaurant> restaurants=response.body().getRestaurants();
                       mAdapter = new RestaurantAdapter(context, restaurantsList);
                        mRecyclerView.setAdapter(mAdapter);
                        RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL);
                        mRecyclerView.addItemDecoration(itemDecoration);
                       for (int i = 0; i < restaurants.size(); i++) {
                            restaurantsList.add(restaurants.get(i).getRestaurant());
                            mAdapter.notifyItemInserted(i);
                        }
                    }

                    @Override
                    public void onFailure(Call<ApiResponse> call, Throwable t) {
                        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                        builder.setMessage("Couldn´t find any nearby restaurants");
                        AlertDialog mDialog = builder.create();
                        mDialog.show();


                    }
                });
    }


    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View mContentView = inflater.inflate(R.layout.restaurants_list, container,false);
        mRecyclerView = mContentView.findViewById(R.id.recycler_view);

        mRecyclerView.setLayoutManager(new LinearLayoutManager(mContentView.getContext()));

        return mContentView;
    }

    @Override
    public void onResume() {
        super.onResume();


    }

    @Override public void onAttach(Activity activity) {
        super.onAttach(activity);
        try{
            listener= (OnRestaurantClickedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnButtonClicked");
        }
    }

    private Retrofit getRetrofit(){
        return new Retrofit.Builder()
                .baseUrl("https://developers.zomato.com/api/v2.1/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    private ZomatoApi getApi(){
        return  getRetrofit().create(ZomatoApi.class);
    }

    private void getLastLocation(){
        if (ActivityCompat.checkSelfPermission(getContext(),
                Manifest.permission.ACCESS_FINE_LOCATION )!= PackageManager.PERMISSION_GRANTED) {
            requestPermissions();
            return;

        }
    }

    private void requestPermissions(){
        ActivityCompat.requestPermissions(getActivity(),
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                REQUEST_FINE_LOCATION);
    }


}

New Code

public class RestaurantsList extends Fragment {
    private RestaurantAdapter mAdapter;
    private RecyclerView mRecyclerView;
    protected static List<Restaurant_> restaurantsList;
    private Context context;
    protected static OnRestaurantClickedListener listener;
    private FirebaseAuth mAuth;
    private static final int REQUEST_FINE_LOCATION=100;
    private LocationRequest mLocationRequest;
    private LocationCallback mLocationCallback;
    private FusedLocationProviderClient mFusedLocationClient;
    private static final String TAG = "LOCATION";


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = getContext();
        mAuth = FirebaseAuth.getInstance();
        restaurantsList= new ArrayList<>(50);
        getLastLocation();
        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());
    }


    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View mContentView = inflater.inflate(R.layout.restaurants_list, container,false);
        mRecyclerView = mContentView.findViewById(R.id.recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(mContentView.getContext()));

        return mContentView;
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override public void onAttach(Activity activity) {
        super.onAttach(activity);
        try{
            listener= (OnRestaurantClickedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnButtonClicked");
        }
    }

    private Retrofit getRetrofit(){
        return new Retrofit.Builder()
                .baseUrl("https://developers.zomato.com/api/v2.1/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    private ZomatoApi getApi(){
        return  getRetrofit().create(ZomatoApi.class);
    }

    private void getLastLocation(){
        if (ActivityCompat.checkSelfPermission(getContext(),
                Manifest.permission.ACCESS_FINE_LOCATION )!= PackageManager.PERMISSION_GRANTED) {
            requestPermissions();
            return;

        }
    }

    private void requestPermissions(){
        ActivityCompat.requestPermissions(getActivity(),
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                REQUEST_FINE_LOCATION);

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == REQUEST_FINE_LOCATION) {
            if (grantResults.length <= 0) {
                // If user interaction was interrupted, the permission request is cancelled and you
                // receive empty arrays.
                Log.i(TAG, "User interaction was cancelled.");
            } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission granted.
                getRestaurants();
            }
        }
    }
    private void getRestaurants(){

        mFusedLocationClient.getLastLocation().addOnSuccessListener(getActivity(), new OnSuccessListener<Location>() {
            @Override
            public void onSuccess(Location location) {
                if (location != null) {
                    getApi().getNearbyRestaurants(location.getLatitude(),location.getLongitude(),20,10000,"rating","desc","75be9f9e2239fe637bf9cb1b46979d91")
                            .enqueue(new Callback<ApiResponse>() {
                                @Override
                                public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
                                    List<Restaurant> restaurants=response.body().getRestaurants();
                                    mAdapter = new RestaurantAdapter(context, restaurantsList);
                                    mRecyclerView.setAdapter(mAdapter);
                                    RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL);
                                    mRecyclerView.addItemDecoration(itemDecoration);
                                    for (int i = 0; i < restaurants.size(); i++) {
                                        restaurantsList.add(restaurants.get(i).getRestaurant());
                                        mAdapter.notifyItemInserted(i);
                                    }
                                }

                                @Override
                                public void onFailure(Call<ApiResponse> call, Throwable t) {
                                    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                                    builder.setMessage("Couldn´t find any nearby restaurants");
                                    AlertDialog mDialog = builder.create();
                                    mDialog.show();


                                }
                            });

                }
            }
        }).addOnFailureListener(getActivity(), new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Toast.makeText( getActivity(),"It wasn´t possible to determine your location", Toast.LENGTH_LONG).show();
            }
        });
    }


}

1 Answers1

0

You're doing two asynchronous tasks that will both complete at some point in the future (fetching location and making Zomato API call). But you're doing them at the same time here. Even though the location code is above the API call code, it's not actually waiting for the location before doing the API call.

What you need to do instead is to move the Zomato API call to its own method. Then call this method from the onSuccess(Location) callback method of the FusedLocationProvider. That way, you're waiting for the location to come in before trying to use the location.

Gavin Wright
  • 3,124
  • 3
  • 14
  • 35
  • I already solved it but I have a little bug. If it is the first time using the app ,it presents the onFailure toast and then presents me the authorization dialog resulting in a null response. Any tip on how to solve this? –  Aug 30 '20 at 17:04
  • You mean the Location permission dialog? – Gavin Wright Aug 30 '20 at 17:05
  • There are a lot of steps in requesting the Location runtime permission, especially if you want to do it correctly: https://github.com/android/location-samples/blob/master/BasicLocation/app/src/main/java/com/google/android/gms/location/sample/basiclocationsample/MainActivity.java – Gavin Wright Aug 30 '20 at 17:10
  • yes. If it is the first time it presents first the toast and only next the permission dialog. If it isn´t the app runs correctly –  Aug 30 '20 at 17:11
  • See the code in the link above. You have to treat it as yet another callback. So you request the Location permission, and then from the `onRequestPermissionsResult()` method you can actually fetch the Location, and then from `onSuccess(Location)` callback method of the FusedLocationProvider you can finally do the Zomato API call. – Gavin Wright Aug 30 '20 at 17:15
  • can I solve it by calling the onStart method on the end of requestPermissions? –  Aug 30 '20 at 17:16
  • Methods like `onCreate()` and `onStart()` are Android system callbacks. You never want to call those yourself. Instead, you'll want to move the FusedLocationClient code to its own method, and call that method from `onRequestPermissionsResult()`. You can see that's what is done with the `getLastLocation()` method here: https://github.com/android/location-samples/blob/c5d837d6739637820b3f92acd906dba5e2a28c7f/BasicLocation/app/src/main/java/com/google/android/gms/location/sample/basiclocationsample/MainActivity.java#L101 – Gavin Wright Aug 30 '20 at 17:20
  • I moved the code to the onRequestPermissionResult but know it is not showing any answer –  Aug 30 '20 at 17:28
  • Are you getting the Location permission request dialog? – Gavin Wright Aug 30 '20 at 17:34
  • In your new code, does it successfully call `getRestaurants()` when the user grants the Location permission? Like if you make a Toast right before that call to `getRestaurants()`, does the Toast get displayed? – Gavin Wright Aug 30 '20 at 17:45
  • Unfortunately, I think we're mixing Fragment code with Activity code at this point. See here for requesting permissions from a Fragment: https://stackoverflow.com/questions/40760625/how-to-check-permission-in-fragment – Gavin Wright Aug 30 '20 at 17:58
  • Good luck dude I have to go to bed! – Gavin Wright Aug 30 '20 at 17:59