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.
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);
}
}
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();
}
});
}
}
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.