Службы определения местоположения Google возвращают нулевое местоположение, когда я использую Retrofit

У меня есть фрагмент, в котором я хочу получить свои текущие координаты, а затем использовать Retrofit, чтобы сделать запрос к Zomato Api, но мое текущее местоположение возвращает значение null. Я попытался удалить код, относящийся к моему вызову API, и приложение вернуло мою правильную широту и долготу. Что я делаю неправильно? Ниже приведен мой класс Java.

Мой Фрагмент

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


}


person Community    schedule 30.08.2020    source источник


Ответы (1)


Вы выполняете две асинхронные задачи, которые завершатся в какой-то момент в будущем (получение местоположения и вызов API Zomato). Но вы делаете их одновременно здесь. Несмотря на то, что код местоположения находится над кодом вызова API, на самом деле он не ожидает местоположения перед выполнением вызова API.

Вместо этого вам нужно переместить вызов Zomato API в собственный метод. Затем вызовите этот метод из метода обратного вызова onSuccess(Location) FusedLocationProvider. Таким образом, вы ждете, пока появится местоположение, прежде чем пытаться его использовать.

person Gavin Wright    schedule 30.08.2020
comment
Я уже решил это ???? но у меня есть небольшая ошибка. Если это первый раз, когда вы используете приложение, оно представляет тост onFailure, а затем представляет мне диалоговое окно авторизации, приводящее к нулевому ответу. Любой совет о том, как решить эту проблему? - person ; 30.08.2020
comment
Вы имеете в виду диалоговое окно разрешения местоположения? - person Gavin Wright; 30.08.2020
comment
Чтобы запросить разрешение среды выполнения Location, нужно выполнить множество шагов, особенно если вы хотите сделать это правильно: github.com/android/location-samples/blob/master/BasicLocation/ - person Gavin Wright; 30.08.2020
comment
да. Если это первый раз, сначала отображается тост, а затем только диалоговое окно разрешения. Если это не так, приложение работает правильно - person ; 30.08.2020
comment
Смотрите код по ссылке выше. Вы должны относиться к этому как к еще одному обратному вызову. Таким образом, вы запрашиваете разрешение на размещение, а затем из метода onRequestPermissionsResult() вы можете фактически получить местоположение, а затем из метода обратного вызова onSuccess(Location) FusedLocationProvider вы, наконец, можете выполнить вызов API Zomato. - person Gavin Wright; 30.08.2020
comment
я могу решить эту проблему, вызвав метод onStart в конце requestPermissions? - person ; 30.08.2020
comment
Такие методы, как onCreate() и onStart(), являются системными обратными вызовами Android. Вы никогда не захотите называть их сами. Вместо этого вы захотите переместить код FusedLocationClient в его собственный метод и вызвать этот метод из onRequestPermissionsResult(). Вы можете увидеть, что делается с помощью метода getLastLocation() здесь: github.com/android/location-samples/blob/ - person Gavin Wright; 30.08.2020
comment
Я переместил код в onRequestPermissionResult, но знаю, что он не показывает никакого ответа - person ; 30.08.2020
comment
Вы получаете диалоговое окно запроса разрешения местоположения? - person Gavin Wright; 30.08.2020
comment
В вашем новом коде он успешно вызывает getRestaurants(), когда пользователь предоставляет разрешение Location? Например, если вы делаете Toast прямо перед этим вызовом getRestaurants(), отображается ли Toast? - person Gavin Wright; 30.08.2020
comment
К сожалению, я думаю, что на данный момент мы смешиваем код фрагмента с кодом действия. См. здесь для запроса разрешений от фрагмента: stackoverflow .com/questions/40760625/ - person Gavin Wright; 30.08.2020
comment
Удачи, чувак, мне пора спать! - person Gavin Wright; 30.08.2020