System Android LocationServices.FusedLocationApi jest przestarzały

89

Nie mogłem zrozumieć, dlaczego LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,mLocationRequest, this);„FusedLocationApi” jest przekreślony i wskazałem, że jest przestarzały. Kliknij tutaj, aby wyświetlić obraz

import android.location.Location;
import android.location.LocationListener;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

public class MaintainerMapActivity extends FragmentActivity implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener{

private GoogleMap mMap;
GoogleApiClient mGoogleApiClient;
Location mLastLocaton;
LocationRequest mLocationRequest;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maintainer_map2);
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}


@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    // Add a marker in Sydney and move the camera
    LatLng sydney = new LatLng(-34, 151);
    mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
    mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}

@Override
public void onLocationChanged(Location location) {

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

}

@Override
public void onProviderEnabled(String provider) {

}

@Override
public void onProviderDisabled(String provider) {

}

@Override
public void onConnected(@Nullable Bundle bundle) {
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(1000);
    mLocationRequest.setFastestInterval(1000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,mLocationRequest, this);
}

@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

}
}
vvvv
źródło
W jaki sposób, jeśli jest przestarzały, jest tam wiersz, sprawdź, czy używam tego LocationServices.FusedLocationApi.requestLocationUpdates (mGoogleApiClient, mLocationRequest, this);
Omar Hayat
@OmarHayat FusedLocationApi jest przekreślony
vvvv
sprawdź swoje zależności, które kompiluję za pomocą tej kompilacji 'com.google.android.gms: play-services-location: 9.4.0'
Omar Hayat
Używasz tego w metodzie oncreate mGoogleApiClient = new GoogleApiClient.Builder (this) .addApi (LocationServices.API) .addConnectionCallbacks (this) .addOnConnectionFailedListener (this) .build ();
Omar Hayat,
@OmarHayat Używałem kompilacji „com.google.android.gms: play-services-location: 11.4.0” i po zmianie na 9.4.0 naprawiło to problem, dlaczego naprawiono po zmianie numeru?
vvvv

Odpowiedzi:

156

Oryginalna odpowiedź

Dzieje się tak, ponieważ zostały FusedLocationProviderApiwycofane w najnowszej wersji usług Google Play. Możesz to sprawdzić tutaj . Oficjalny przewodnik sugeruje teraz użycie FusedLocationProviderClient . Szczegółowy przewodnik znajdziesz tutaj .

np. wewnątrz onCreate()lub onViewCreated()utwórz FusedLocationProviderClientinstancję

Kotlin

val fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireContext())

a aby poprosić o ostatnią znaną lokalizację, wystarczy zadzwonić

fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? ->
            location?.let { it: Location ->
                // Logic to handle location object
            } ?: kotlin.run {
                // Handle Null case or Request periodic location update https://developer.android.com/training/location/receive-location-updates
            }
        }

Jawa

FusedLocationProviderClient fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireContext());

i

fusedLocationClient.getLastLocation().addOnSuccessListener(requireActivity(), location -> {
        if (location != null) {
            // Logic to handle location object
        } else {
            // Handle null case or Request periodic location update https://developer.android.com/training/location/receive-location-updates
        }
    });

Proste, prawda?


Ważna aktualizacja (24 października 2017 r.):

Wczoraj Google zaktualizowała swoją oficjalną stronę programisty z ostrzeżeniem , który mówi

Kontynuuj korzystanie z klasy FusedLocationProviderApi i nie przeprowadzaj migracji do klasy FusedLocationProviderClient do czasu udostępnienia usług Google Play w wersji 12.0.0, która ma zostać dostarczona na początku 2018 r. Użycie FusedLocationProviderClient przed wersją 12.0.0 powoduje awarię aplikacji klienckiej, gdy Usługi Google Play są aktualizowane na urządzeniu. Przepraszamy za wszelkie związane z tym niedogodności.

ostrzeżenie Myślę więc, że powinniśmy nadal korzystać z wycofanej wersji, LocationServices.FusedLocationApidopóki Google nie rozwiąże problemu.


Ostatnia aktualizacja (21 listopada 2017 r.):

Ostrzeżenie minęło. Usługi Google Play 11.6 6 listopada 2017 r., Informacja o wydaniu mówi: Naprawiono problem FusedLocationProviderClient, który czasami powodował awarie podczas aktualizacji usług Google Play.Myślę, że usługi Play nie ulegną awarii, gdy aktualizują się w tle. Więc możemy FusedLocationProviderClientteraz użyć nowego .

Somesh Kumar
źródło
3
Uwielbiam sposób, w jaki dokumenty Google wciąż mówią Ci o używaniu starego interfejsu API: developer.android.com/training/location/ ...
mxcl
czy getLastLocation () robi to, co robi LocationServices.FusedLocationApi.requestLocationUpdates ()? Jak dotąd dziwne jest to, że dokumentacja wciąż wskazuje na ten stary sposób. To zagmatwane. developer.android.com/training/location/…
Juan Mendez
@JuanMendez Zgadzam się. Muszą popracować nad utrzymaniem odpowiednich, aktualnych przykładów. btw getLastLocation()zwraca tylko najbardziej aktualną znaną lokalizację urządzenia .. możesz zażądać aktualizacji lokalizacji nową requestLocationUpdates(LocationRequest request, PendingIntent callbackIntent)metodą.
Somesh Kumar
@SomeshKumar, dzięki. tak, to jest metoda, której używałem. W międzyczasie trzymam się 11.2.0.
Juan Mendez
2
@Fraid Tak, ostrzeżenie zniknęło ... a podany przez Ciebie link stwierdza również, że nowa wersja usług Google Play nie ulegnie awarii, jeśli użytkownik zaktualizuje aplikację. Myślę, że powinienem teraz zaktualizować moją odpowiedź.
Somesh Kumar
16
   // Better to use GoogleApiClient to show device location. I am using this way in my aap.

    public class SuccessFragment extends Fragment{
        private TextView txtLatitude, txtLongitude, txtAddress;
        // private AddressResultReceiver mResultReceiver;
        // removed here because cause wrong code when implemented and
        // its not necessary like the author says

        //Define fields for Google API Client
        private FusedLocationProviderClient mFusedLocationClient;
        private Location lastLocation;
        private LocationRequest locationRequest;
        private LocationCallback mLocationCallback;

        private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 14;

        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_location, container, false);

            txtLatitude = (TextView) view.findViewById(R.id.txtLatitude);
            txtLongitude = (TextView) view.findViewById(R.id.txtLongitude);
            txtAddress = (TextView) view.findViewById(R.id.txtAddress);

            // mResultReceiver = new AddressResultReceiver(null);
            // cemented as above explained
            try {
                mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());
                mFusedLocationClient.getLastLocation()
                        .addOnSuccessListener(getActivity(), new OnSuccessListener<Location>() {
                            @Override
                            public void onSuccess(Location location) {
                                // Got last known location. In some rare situations this can be null.
                                if (location != null) {
                                    // Logic to handle location object
                                    txtLatitude.setText(String.valueOf(location.getLatitude()));
                                    txtLongitude.setText(String.valueOf(location.getLongitude()));
                                    if (mResultReceiver != null)
                                        txtAddress.setText(mResultReceiver.getAddress());
                                }
                            }
                        });
                locationRequest = LocationRequest.create();
                locationRequest.setInterval(5000);
                locationRequest.setFastestInterval(1000);
                if (txtAddress.getText().toString().equals(""))
                    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
                else
                    locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);

                mLocationCallback = new LocationCallback() {
                    @Override
                    public void onLocationResult(LocationResult locationResult) {
                        for (Location location : locationResult.getLocations()) {
                            // Update UI with location data
                            txtLatitude.setText(String.valueOf(location.getLatitude()));
                            txtLongitude.setText(String.valueOf(location.getLongitude()));
                        }
                    }

                    ;
                };
            } catch (SecurityException ex) {
                ex.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return view;
        }

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

            if (!checkPermissions()) {
                startLocationUpdates();
                requestPermissions();
            } else {
                getLastLocation();
                startLocationUpdates();
            }
        }

        @Override
        public void onPause() {
            stopLocationUpdates();
            super.onPause();
        }

        /**
         * Return the current state of the permissions needed.
         */
        private boolean checkPermissions() {
            int permissionState = ActivityCompat.checkSelfPermission(getActivity(),
                    Manifest.permission.ACCESS_COARSE_LOCATION);
            return permissionState == PackageManager.PERMISSION_GRANTED;
        }

        private void startLocationPermissionRequest() {
            ActivityCompat.requestPermissions(getActivity(),
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                    REQUEST_PERMISSIONS_REQUEST_CODE);
        }


        private void requestPermissions() {
            boolean shouldProvideRationale =
                    ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
                            Manifest.permission.ACCESS_COARSE_LOCATION);

            // Provide an additional rationale to the user. This would happen if the user denied the
            // request previously, but didn't check the "Don't ask again" checkbox.
            if (shouldProvideRationale) {
                Log.i(TAG, "Displaying permission rationale to provide additional context.");

                showSnackbar(R.string.permission_rationale, android.R.string.ok,
                        new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                // Request permission
                                startLocationPermissionRequest();
                            }
                        });

            } else {
                Log.i(TAG, "Requesting permission");
                // Request permission. It's possible this can be auto answered if device policy
                // sets the permission in a given state or the user denied the permission
                // previously and checked "Never ask again".
                startLocationPermissionRequest();
            }
        }

        /**
         * Callback received when a permissions request has been completed.
         */
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                               @NonNull int[] grantResults) {
            Log.i(TAG, "onRequestPermissionResult");
            if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
                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.
                    getLastLocation();
                } else {
                    // Permission denied.

                    // Notify the user via a SnackBar that they have rejected a core permission for the
                    // app, which makes the Activity useless. In a real app, core permissions would
                    // typically be best requested during a welcome-screen flow.

                    // Additionally, it is important to remember that a permission might have been
                    // rejected without asking the user for permission (device policy or "Never ask
                    // again" prompts). Therefore, a user interface affordance is typically implemented
                    // when permissions are denied. Otherwise, your app could appear unresponsive to
                    // touches or interactions which have required permissions.
                    showSnackbar(R.string.permission_denied_explanation, R.string.settings,
                            new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                    // Build intent that displays the App settings screen.
                                    Intent intent = new Intent();
                                    intent.setAction(
                                            Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                    Uri uri = Uri.fromParts("package",
                                            BuildConfig.APPLICATION_ID, null);
                                    intent.setData(uri);
                                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                    startActivity(intent);
                                }
                            });
                }
            }
        }


        /**
         * Provides a simple way of getting a device's location and is well suited for
         * applications that do not require a fine-grained location and that do not need location
         * updates. Gets the best and most recent location currently available, which may be null
         * in rare cases when a location is not available.
         * <p>
         * Note: this method should be called after location permission has been granted.
         */
        @SuppressWarnings("MissingPermission")
        private void getLastLocation() {
            mFusedLocationClient.getLastLocation()
                    .addOnCompleteListener(getActivity(), new OnCompleteListener<Location>() {
                        @Override
                        public void onComplete(@NonNull Task<Location> task) {
                            if (task.isSuccessful() && task.getResult() != null) {
                                lastLocation = task.getResult();

                                txtLatitude.setText(String.valueOf(lastLocation.getLatitude()));
                                txtLongitude.setText(String.valueOf(lastLocation.getLongitude()));

                            } else {
                                Log.w(TAG, "getLastLocation:exception", task.getException());
                                showSnackbar(getString(R.string.no_location_detected));
                            }
                        }
                    });
        }

        private void stopLocationUpdates() {
            mFusedLocationClient.removeLocationUpdates(mLocationCallback);
        }

        private void startLocationUpdates() {
            if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    ActivityCompat#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)
                // to handle the case where the user grants the permission. See the documentation
                // for ActivityCompat#requestPermissions for more details.
                return;
            }
            mFusedLocationClient.requestLocationUpdates(locationRequest, mLocationCallback, null);
        }

        // private void showSnackbar(final String text) {
        //    if (canvasLayout != null) {
        //        Snackbar.make(canvasLayout, text, Snackbar.LENGTH_LONG).show();
        //    }
        //}
        // this also cause wrong code and as I see it dont is necessary
        // because the same method which is really used


        private void showSnackbar(final int mainTextStringId, final int actionStringId,
                                  View.OnClickListener listener) {
            Snackbar.make(getActivity().findViewById(android.R.id.content),
                    getString(mainTextStringId),
                    Snackbar.LENGTH_INDEFINITE)
                    .setAction(getString(actionStringId), listener).show();
        }
    }

I nasz fragment_location.xml

       <?xml version="1.0" encoding="utf-8"?>
       <LinearLayout 
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/locationLayout"
            android:layout_below="@+id/txtAddress"
            android:layout_width="match_parent"
            android:layout_height="@dimen/activity_margin_30dp"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/txtLatitude"
                android:layout_width="@dimen/activity_margin_0dp"
                android:layout_height="@dimen/activity_margin_30dp"
                android:layout_weight="0.5"
                android:gravity="center"
                android:hint="@string/latitude"
                android:textAllCaps="false"
                android:textColorHint="@color/colorPrimaryDark"
                android:textColor="@color/colorPrimaryDark" />

            <TextView
                android:id="@+id/txtLongitude"
                android:layout_width="@dimen/activity_margin_0dp"
                android:layout_height="@dimen/activity_margin_30dp"
                android:layout_weight="0.5"
                android:gravity="center"
                android:hint="@string/longitude"
                android:textAllCaps="false"
                android:textColorHint="@color/colorPrimary"
                android:textColor="@color/colorPrimary" />
        </LinearLayout>
JoboFive
źródło
usuń tę linię. A reszta kodu będzie działać dla Ciebie
JoboFive
nie można znaleźć lokalizacji w następnym interwale
VY
@Vishal Otrzymuję lokalizację w czasie rzeczywistym za każdym razem, gdy musisz sprawdzić pozwolenie na lokalizację w manifeście, a także w kodzie wewnętrznym
JoboFive
Dziękuję za twój kod. Ale mam problem, jeśli potrzebuję lokalizacji co 100 metrów i wysyłam ją na serwer, co mam zrobić? Proszę pomóż.
Pravinsingh Waghela
Użyj w ten sposób: locationRequest = LocationRequest.create () .setPriority (LocationRequest.PRIORITY_HIGH_ACCURACY) .setInterval (90000) .setSmallestDisplacement (10) .setFastestInterval (10000);
JoboFive
2

Tak, jest przestarzały!
Oto kilka punktów, których będziesz potrzebować podczas korzystania z nowego FusedLocationProviderClient .

  1. zaimportuj jako import com.google.android.gms.location.FusedLocationProviderClient;😅
  2. Zauważyłem, że implementujesz interfejs LocationListener . W metodzie mFusedLocationClient.requestLocationUpdates () teraz nie przyjmuje LocationListener jako parametru. Możesz podać LocationCallback . Ponieważ jest to klasa abstrakcyjna, nie można jej zaimplementować jak LocationListener. Utwórz metodę wywołania zwrotnego i przekaż ją zamiast „this”, jak wspomniano w przewodniku Google . zaimportuj jakoimport com.google.android.gms.location.LocationCallback;
  3. Dzięki LocationCallback będziesz mieć onLocationResult () zamiast onLocationChanged () . Zwraca obiekt LocationResult zamiast obiektu Location. Użyj LocationResult.getLastLocation (), aby uzyskać najnowszą lokalizację dostępną w tym obiekcie wynikowym. Zaimportuj jakoimport com.google.android.gms.location.LocationResult;
Malith
źródło
2

Tak, zostało wycofane. FusedLocationProviderClientjest łatwiejsze niż FusedLocationProviderApi, ponieważ FusedLocationProviderApizwykle wymaga GoogleApiClientteż, z którym musimy się połączyć Google Play Serviceręcznie. Jeśli wcześniej korzystałeś GoogleApiClient, teraz GoogleApiClientnie jest już potrzebne ( więcej tutaj ).

Aby uzyskać ostatnią lokalizację, możesz użyć tej funkcji:

import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.tasks.OnCompleteListener;

public class MainActivity extends AppCompatActivity{
//before public class MainActivity extends AppCompatActivity implements LocationListener,...,...


private static final String TAG = "MainActivity";
public static final int MY_PERMISSIONS_REQUEST_FINE_LOCATION = 101;
private FusedLocationProviderClient mFusedLocationClient;
private Location mGetedLocation;

private double currentLat, currentLng;

private void getLastLocation() {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_FINE_LOCATION);
        }
        return;
    }
    mFusedLocationClient.getLastLocation()
            .addOnCompleteListener(this, new OnCompleteListener<Location>() {
                @Override
                public void onComplete(@NonNull Task<Location> task) {
                    if (task.isSuccessful() && task.getResult() != null) {
                        mGetedLocation = task.getResult();
                        currentLat = mGetedLocation.getLatitude();
                        currentLng = mGetedLocation.getLongitude();
                        //updateUI();
                    }else{
                        Log.e(TAG, "no location detected");
                        Log.w(TAG, "getLastLocation:exception", task.getException());
                    }
                }
            });

}
Latief Anwar
źródło
-1

Problem dotyczy wyciągu importu

Usuń to

import android.location.LocationListener;

Dodaj

import com.google.android.gms.location.LocationListener;
dx arout
źródło
-1

Spraw, aby Twoja aktywność zaimplementowała LocationListener z usług Google, a nie z systemu operacyjnego Android, to działało dla mnie.

Karim Elbahi
źródło
-1

użyj getFusedLocationProviderClient zamiast LocationServices.FusedLocationApi.

Kotlin

activity?.let { activity ->
      val client = LocationServices.getFusedLocationProviderClient(activity)
           client.lastLocation.addOnCompleteListener(activity, OnCompleteListener<Location> {
              // it.result.latitude
              // it.result.longitude
      })
}

Jawa

FusedLocationProviderClient client =
        LocationServices.getFusedLocationProviderClient(this);

// Get the last known location
client.getLastLocation()
        .addOnCompleteListener(this, new OnCompleteListener<Location>() {
            @Override
            public void onComplete(@NonNull Task<Location> task) {
                // ...
            }
        });
Rasoul Miri
źródło