Android에서 사용자의 현재 위치를 얻는 가장 간단하고 강력한 방법은 무엇입니까?
LocationManager
Android 의 API는 사용자 위치에 대한 대략적인 근사치를 가끔 필요로하는 애플리케이션에 사용하는 것이 약간 고통스러운 것 같습니다.
제가 작업중인 앱은 그 자체로 위치 앱은 아니지만 주변 업체 목록을 표시하려면 사용자의 위치를 가져와야합니다. 사용자가 이리저리 움직이고 있는지에 대해 걱정할 필요가 없습니다.
내가 원하는 것은 다음과 같습니다.
- 사용자에게 주변 위치 목록을 표시합니다.
Activity
X 에서 필요할 때까지 사용할 수 있도록 사용자 위치를 미리로드합니다 .- 나는 업데이트의 정확성이나 빈도에 특별히 신경 쓰지 않습니다. 길을 벗어나지 않는 한 한 위치를 잡는 것으로 충분합니다. 내가 화려하게하고 싶다면 몇 분마다 한 번씩 위치를 업데이트 할 것이지만 그다지 중요하지는 않습니다.
- GPS 또는 네트워크 위치 공급자가있는 모든 장치에서 작동합니다.
그렇게 어렵지 않을 것 같지만 두 개의 서로 다른 위치 공급자 (GPS 및 NETWORK)를 가동하고 각각의 수명주기를 관리해야하는 것 같습니다. 뿐만 아니라, # 2를 만족시키기 위해 여러 활동에서 동일한 코드를 복제해야합니다. 저는 getBestProvider()
과거에 하나의 위치 제공 업체 만 사용하도록 솔루션을 줄이려고 시도했지만 실제로 최상의 결과를 제공 할 제공 업체가 아닌 최상의 "이론적"제공 업체 만 제공하는 것 같습니다.
이를 수행하는 더 간단한 방법이 있습니까?
내가하는 일은 다음과 같습니다.
- 우선 어떤 공급자가 활성화되어 있는지 확인합니다. 일부는 장치에서 비활성화되고 일부는 응용 프로그램 매니페스트에서 비활성화 될 수 있습니다.
- 사용 가능한 공급자가 있으면 위치 수신기와 시간 초과 타이머를 시작합니다. 내 예에서는 20 초이며 GPS에 충분하지 않을 수 있으므로 확대 할 수 있습니다.
- 위치 수신기에서 업데이트를 받으면 제공된 값을 사용합니다. 청취자와 타이머를 중지합니다.
- 업데이트를받지 못하고 타이머가 경과하면 마지막으로 알려진 값을 사용해야합니다.
- 사용 가능한 공급자에서 마지막으로 알려진 값을 가져와 가장 최근의 값을 선택합니다.
내 수업을 사용하는 방법은 다음과 같습니다.
LocationResult locationResult = new LocationResult(){
@Override
public void gotLocation(Location location){
//Got the location!
}
};
MyLocation myLocation = new MyLocation();
myLocation.getLocation(this, locationResult);
다음은 MyLocation 클래스입니다.
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
public class MyLocation {
Timer timer1;
LocationManager lm;
LocationResult locationResult;
boolean gps_enabled=false;
boolean network_enabled=false;
public boolean getLocation(Context context, LocationResult result)
{
//I use LocationResult callback class to pass location value from MyLocation to user code.
locationResult=result;
if(lm==null)
lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
//exceptions will be thrown if provider is not permitted.
try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){}
try{network_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){}
//don't start listeners if no provider is enabled
if(!gps_enabled && !network_enabled)
return false;
if(gps_enabled)
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if(network_enabled)
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timer1=new Timer();
timer1.schedule(new GetLastLocation(), 20000);
return true;
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerNetwork);
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
};
class GetLastLocation extends TimerTask {
@Override
public void run() {
lm.removeUpdates(locationListenerGps);
lm.removeUpdates(locationListenerNetwork);
Location net_loc=null, gps_loc=null;
if(gps_enabled)
gps_loc=lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(network_enabled)
net_loc=lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
//if there are both values use the latest one
if(gps_loc!=null && net_loc!=null){
if(gps_loc.getTime()>net_loc.getTime())
locationResult.gotLocation(gps_loc);
else
locationResult.gotLocation(net_loc);
return;
}
if(gps_loc!=null){
locationResult.gotLocation(gps_loc);
return;
}
if(net_loc!=null){
locationResult.gotLocation(net_loc);
return;
}
locationResult.gotLocation(null);
}
}
public static abstract class LocationResult{
public abstract void gotLocation(Location location);
}
}
누군가 내 논리를 수정하고 싶을 수도 있습니다. 예를 들어 네트워크 공급자로부터 업데이트를받는 경우 리스너를 중지하지 않고 계속 기다리십시오. GPS는 더 정확한 데이터를 제공하므로 기다릴 가치가 있습니다. 타이머가 경과하고 GPS가 아닌 네트워크에서 업데이트를받은 경우 네트워크에서 제공 한 값을 사용할 수 있습니다.
또 다른 접근 방식은 LocationClient http://developer.android.com/training/location/retrieve-current.html 을 사용하는 것 입니다. 하지만 사용자 기기에 Google Play 서비스 apk를 설치해야합니다.
최상의 정확한 사용자 위치를 얻는 방법을 찾는 최상의 구현을 찾은 후 모든 최상의 방법을 결합하고 다음 클래스를 생각해 냈습니다.
/**
* Retrieve accurate location from GPS or network services.
*
*
* Class usage example:
*
* public void onCreate(Bundle savedInstanceState) {
* ...
* my_location = new MyLocation();
* my_location.init(main.this, locationResult);
* }
*
*
* public LocationResult locationResult = new LocationResult(){
* @Override
* public void gotLocation(final Location location){
* // do something
* location.getLongitude();
* location.getLatitude();
* }
* };
*/
class MyLocation{
/**
* If GPS is enabled.
* Use minimal connected satellites count.
*/
private static final int min_gps_sat_count = 5;
/**
* Iteration step time.
*/
private static final int iteration_timeout_step = 500;
LocationResult locationResult;
private Location bestLocation = null;
private Handler handler = new Handler();
private LocationManager myLocationManager;
public Context context;
private boolean gps_enabled = false;
private int counts = 0;
private int sat_count = 0;
private Runnable showTime = new Runnable() {
public void run() {
boolean stop = false;
counts++;
System.println("counts=" + counts);
//if timeout (1 min) exceeded, stop tying
if(counts > 120){
stop = true;
}
//update last best location
bestLocation = getLocation(context);
//if location is not ready or don`t exists, try again
if(bestLocation == null && gps_enabled){
System.println("BestLocation not ready, continue to wait");
handler.postDelayed(this, iteration_timeout_step);
}else{
//if best location is known, calculate if we need to continue to look for better location
//if gps is enabled and min satellites count has not been connected or min check count is smaller then 4 (2 sec)
if(stop == false && !needToStop()){
System.println("Connected " + sat_count + " sattelites. continue waiting..");
handler.postDelayed(this, iteration_timeout_step);
}else{
System.println("#########################################");
System.println("BestLocation finded return result to main. sat_count=" + sat_count);
System.println("#########################################");
// removing all updates and listeners
myLocationManager.removeUpdates(gpsLocationListener);
myLocationManager.removeUpdates(networkLocationListener);
myLocationManager.removeGpsStatusListener(gpsStatusListener);
sat_count = 0;
// send best location to locationResult
locationResult.gotLocation(bestLocation);
}
}
}
};
/**
* Determine if continue to try to find best location
*/
private Boolean needToStop(){
if(!gps_enabled){
return true;
}
else if(counts <= 4){
return false;
}
if(sat_count < min_gps_sat_count){
//if 20-25 sec and 3 satellites found then stop
if(counts >= 40 && sat_count >= 3){
return true;
}
return false;
}
}
return true;
}
/**
* Best location abstract result class
*/
public static abstract class LocationResult{
public abstract void gotLocation(Location location);
}
/**
* Initialize starting values and starting best location listeners
*
* @param Context ctx
* @param LocationResult result
*/
public void init(Context ctx, LocationResult result){
context = ctx;
locationResult = result;
myLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
gps_enabled = (Boolean) myLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
bestLocation = null;
counts = 0;
// turning on location updates
myLocationManager.requestLocationUpdates("network", 0, 0, networkLocationListener);
myLocationManager.requestLocationUpdates("gps", 0, 0, gpsLocationListener);
myLocationManager.addGpsStatusListener(gpsStatusListener);
// starting best location finder loop
handler.postDelayed(showTime, iteration_timeout_step);
}
/**
* GpsStatus listener. OnChainged counts connected satellites count.
*/
public final GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
public void onGpsStatusChanged(int event) {
if(event == GpsStatus.GPS_EVENT_SATELLITE_STATUS){
try {
// Check number of satellites in list to determine fix state
GpsStatus status = myLocationManager.getGpsStatus(null);
Iterable<GpsSatellite>satellites = status.getSatellites();
sat_count = 0;
Iterator<GpsSatellite>satI = satellites.iterator();
while(satI.hasNext()) {
GpsSatellite satellite = satI.next();
System.println("Satellite: snr=" + satellite.getSnr() + ", elevation=" + satellite.getElevation());
sat_count++;
}
} catch (Exception e) {
e.printStackTrace();
sat_count = min_gps_sat_count + 1;
}
System.println("#### sat_count = " + sat_count);
}
}
};
/**
* Gps location listener.
*/
public final LocationListener gpsLocationListener = new LocationListener(){
@Override
public void onLocationChanged(Location location){
}
public void onProviderDisabled(String provider){}
public void onProviderEnabled(String provider){}
public void onStatusChanged(String provider, int status, Bundle extras){}
};
/**
* Network location listener.
*/
public final LocationListener networkLocationListener = new LocationListener(){
@Override
public void onLocationChanged(Location location){
}
public void onProviderDisabled(String provider){}
public void onProviderEnabled(String provider){}
public void onStatusChanged(String provider, int status, Bundle extras){}
};
/**
* Returns best location using LocationManager.getBestProvider()
*
* @param context
* @return Location|null
*/
public static Location getLocation(Context context){
System.println("getLocation()");
// fetch last known location and update it
try {
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
String strLocationProvider = lm.getBestProvider(criteria, true);
System.println("strLocationProvider=" + strLocationProvider);
Location location = lm.getLastKnownLocation(strLocationProvider);
if(location != null){
return location;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
이 클래스는 min_gps_sat_count
GPS가 활성화 된 경우 위성 에 연결을 시도합니다 . Else는 LocationManager.getBestProvider()
위치를 반환합니다 . 코드를 확인하세요!
Fedor의 솔루션으로 콜백 실행을 여러 번 경험했습니다 gotLocation
. gotLocation 메서드가 '충분히 길다' 인 경우 재정의 된 메서드 의 경쟁 조건 으로 인한 것 같습니다 . 확실 하지 않지만 Looper 대기열에 새 메시지를 넣는 것을 방지하지만 이미 대기열에 넣었지만 아직 사용하지 않은 메시지는 제거하지 않습니다. 따라서 경쟁 조건.LocationListener.onLocationChanged
removeUpdates
이 잘못된 동작의 가능성을 줄이기 위해 onLocationChanged 이벤트를 시작하기 전에 removeUpdates를 호출 할 수 있지만 여전히 경쟁 조건이 있습니다.
가장 좋은 솔루션 I의 발견되었습니다 교체하는 것입니다 requestLocationUpdates
함께 requestSingleUpdate
.
이것은 루퍼 스레드에 메시지를 보내기 위해 핸들러를 사용하는 Fedor의 솔루션을 기반으로 한 내 버전입니다.
public class LocationResolver {
private Timer timer;
private LocationManager locationManager;
private LocationResult locationResult;
private boolean gpsEnabled = false;
private boolean networkEnabled = false;
private Handler locationTimeoutHandler;
private final Callback locationTimeoutCallback = new Callback() {
public boolean handleMessage(Message msg) {
locationTimeoutFunc();
return true;
}
private void locationTimeoutFunc() {
locationManager.removeUpdates(locationListenerGps);
locationManager.removeUpdates(locationListenerNetwork);
Location networkLocation = null, gpsLocation = null;
if (gpsEnabled)
gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (networkEnabled)
networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
// if there are both values use the latest one
if (gpsLocation != null && networkLocation != null) {
if (gpsLocation.getTime() > networkLocation.getTime())
locationResult.gotLocation(gpsLocation);
else
locationResult.gotLocation(networkLocation);
return;
}
if (gpsLocation != null) {
locationResult.gotLocation(gpsLocation);
return;
}
if (networkLocation != null) {
locationResult.gotLocation(networkLocation);
return;
}
locationResult.gotLocation(null);
}
};
private final LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timer.cancel();
locationResult.gotLocation(location);
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerNetwork);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
private final LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timer.cancel();
locationResult.gotLocation(location);
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
public void prepare() {
locationTimeoutHandler = new Handler(locationTimeoutCallback);
}
public synchronized boolean getLocation(Context context, LocationResult result, int maxMillisToWait) {
locationResult = result;
if (locationManager == null)
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
// exceptions will be thrown if provider is not permitted.
try {
gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch (Exception ex) {
}
try {
networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception ex) {
}
// don't start listeners if no provider is enabled
if (!gpsEnabled && !networkEnabled)
return false;
if (gpsEnabled)
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, locationListenerGps, Looper.myLooper());
//locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if (networkEnabled)
locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, locationListenerNetwork, Looper.myLooper());
//locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timer = new Timer();
timer.schedule(new GetLastLocationTask(), maxMillisToWait);
return true;
}
private class GetLastLocationTask extends TimerTask {
@Override
public void run() {
locationTimeoutHandler.sendEmptyMessage(0);
}
}
public static abstract class LocationResult {
public abstract void gotLocation(Location location);
}
}
다음과 같이 사용자 정의 된 루퍼 스레드에서이 클래스를 사용합니다.
public class LocationGetter {
private final Context context;
private Location location = null;
private final Object gotLocationLock = new Object();
private final LocationResult locationResult = new LocationResult() {
@Override
public void gotLocation(Location location) {
synchronized (gotLocationLock) {
LocationGetter.this.location = location;
gotLocationLock.notifyAll();
Looper.myLooper().quit();
}
}
};
public LocationGetter(Context context) {
if (context == null)
throw new IllegalArgumentException("context == null");
this.context = context;
}
public synchronized Coordinates getLocation(int maxWaitingTime, int updateTimeout) {
try {
final int updateTimeoutPar = updateTimeout;
synchronized (gotLocationLock) {
new Thread() {
public void run() {
Looper.prepare();
LocationResolver locationResolver = new LocationResolver();
locationResolver.prepare();
locationResolver.getLocation(context, locationResult, updateTimeoutPar);
Looper.loop();
}
}.start();
gotLocationLock.wait(maxWaitingTime);
}
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if (location != null)
coordinates = new Coordinates(location.getLatitude(), location.getLongitude());
else
coordinates = Coordinates.UNDEFINED;
return coordinates;
}
}
여기서 Coordinates는 위도와 경도라는 두 가지 속성이있는 간단한 클래스입니다.
현재 위치 GPS 좌표를 얻기 위해 단계별 설명이 포함 된 작은 응용 프로그램을 만들었습니다.
아래 URL의 전체 예제 소스 코드 :
작동 원리보기 :
이 권한을 매니페스트 파일에 추가하기 만하면됩니다.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"> </uses-permission>
다음과 같이 LocationManager 인스턴스를 만듭니다.
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
GPS 활성화 여부 확인
그런 다음 LocationListener를 구현하고 좌표를 가져옵니다.
LocationListener locationListener = new MyLocationListener(); locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 5000, 10, locationListener);
수행 할 샘플 코드는 다음과 같습니다.
/*----------Listener class to get coordinates ------------- */
private class MyLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location loc) {
editLocation.setText("");
pb.setVisibility(View.INVISIBLE);
Toast.makeText(
getBaseContext(),
"Location changed: Lat: " + loc.getLatitude() + " Lng: "
+ loc.getLongitude(), Toast.LENGTH_SHORT).show();
String longitude = "Longitude: " + loc.getLongitude();
Log.v(TAG, longitude);
String latitude = "Latitude: " + loc.getLatitude();
Log.v(TAG, latitude);
/*-------to get City-Name from coordinates -------- */
String cityName = null;
Geocoder gcd = new Geocoder(getBaseContext(), Locale.getDefault());
List<Address> addresses;
try {
addresses = gcd.getFromLocation(loc.getLatitude(),
loc.getLongitude(), 1);
if (addresses.size() > 0)
System.out.println(addresses.get(0).getLocality());
cityName = addresses.get(0).getLocality();
} catch (IOException e) {
e.printStackTrace();
}
String s = longitude + "\n" + latitude + "\n\nMy Current City is: "
+ cityName;
editLocation.setText(s);
}
@Override
public void onProviderDisabled(String provider) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
}
항상 LocationManager.getLastKnownLocation ()을 사용할 수 있지만 오래되었을 수 있다고 말합니다.
일반적인 위치를 얻는 간단한 방법은 네트워크에 등록하는 것입니다 (일반적으로 매우 빠름).
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 1000, 1000, this);
그리고 나서
locationManager.removeUpdates(this);
onLocationChanged()
리스너 의 메서드에서.
여기 demonuts.com 에서 현재 위치를 다루는 자세한 자습서를 작성 했습니다 . 여기에서 자세한 설명을 찾을 수 있으며 더 나은 이해를 위해 전체 데모 소스 코드를 다운로드 할 수도 있습니다.
이미 많은 답변이 있지만 Google API를 사용하여 위치를 얻는 최신 방법을 보여주고 싶습니다. 그래서 새로운 프로그래머는 새로운 방법을 사용할 수 있습니다.
먼저 이것을 gradle 파일에 넣으십시오.
compile 'com.google.android.gms:play-services:8.4.0'
그런 다음 필요한 인터페이스를 구현하십시오.
public class MainActivity extends BaseActivitiy implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener
인스턴스 선언
private GoogleApiClient mGoogleApiClient;
private Location mLocation;
private LocationManager locationManager;
private LocationRequest mLocationRequest;
이것을 넣어 onCreate()
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
마침내 필요한 방법을 재정의하십시오.
@Override
public void onConnected(Bundle bundle) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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;
}
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLocation == null){
startLocationUpdates();
}
if (mLocation != null) {
double latitude = mLocation.getLatitude();
double longitude = mLocation.getLongitude();
} else {
// Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show();
}
}
protected void startLocationUpdates() {
// Create the location request
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
// Request location updates
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
Log.d("reque", "--->>>>");
}
@Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection Suspended");
mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode());
}
@Override
public void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
@Override
public void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
@Override
public void onLocationChanged(Location location) {
}
앱을 실행하기 전에 장치에서 GPS를 시작하는 것을 잊지 마십시오.
위치 기반 서비스 가 GPS 이외의 다른 인프라에서 위치를 가져올 수 있는지 확실하지 않지만 해당 기사에 따르면 가능해 보입니다.
응용 프로그램은 여러 유형의 위치 지정 방법을 호출 할 수 있습니다.
휴대폰 네트워크 사용 : 현재 셀 ID를 사용하여 장치가 통신하고있는 BTS (Base Transceiver Station) 및 해당 BTS의 위치를 식별 할 수 있습니다. 분명히이 방법의 정확도는 셀의 크기에 따라 다르며 매우 정확하지 않을 수 있습니다. GSM 셀의 직경은 2 ~ 20km입니다. 셀 ID와 함께 사용되는 다른 기술은 150 미터 이내의 정확도를 달성 할 수 있습니다.
위성 사용 : 미국 국방부가 제어하는 GPS (Global Positioning System)는 지구 궤도를 도는 24 개의 위성 별자리를 사용합니다. GPS는 서로 다른 위성의 신호가 수신기에 도달하는 데 걸리는 시간 차이를 계산하여 장치의 위치를 결정합니다. GPS 신호는 인코딩되므로 모바일 장치에 GPS 수신기가 장착되어 있어야합니다. GPS는 잠재적으로 가장 정확한 방법이지만 (GPS 수신기가 하늘을 볼 수있는 경우 4 ~ 40 미터 사이) 몇 가지 단점이 있습니다. 추가 하드웨어는 비용이 많이 들고 사용 중 배터리를 소모하며 약간의 따뜻함이 필요합니다. 눈에 보이는 위성에 대한 초기 수정을 얻기 위해 콜드 스타트 후 또한 위성 가시성이 간헐적으로 발생하는 도시에서 "협곡 효과"를 겪습니다.
단거리 포지셔닝 비콘 사용 : 단일 건물과 같이 상대적으로 작은 지역에서 근거리 통신망은 다른 서비스와 함께 위치를 제공 할 수 있습니다. 예를 들어, 적절하게 장착 된 장치는 근거리 위치 확인에 Bluetooth를 사용할 수 있습니다.
아래 코드를 사용하면 최상의 공급자가 제공됩니다.
String locCtx = Context.LOCATION_SERVICE;
LocationManager locationMgr = (LocationManager) ctx.getSystemService(locCtx);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_LOW);
String provider = locationMgr.getBestProvider(criteria, true);
System.out.println("Best Available provider::::"+provider);
실제로 두 공급자 (GPS 및 NETWORK)를 사용할 수 있습니다. 그리고 그들은 단지 공개 청취자를 공유합니다.
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10 * 1000, (float) 10.0, listener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 90 * 1000, (float) 10.0, listener);
이는 OnLocationChanged()
메서드가 항상 제 시간에 호출되어야하기 때문에 필요합니다.
이를 수행하는 권장 방법은 다음을 사용하는 것입니다 LocationClient
.
먼저 위치 업데이트 간격 값을 정의합니다. 필요에 맞게 조정하십시오.
private static final int MILLISECONDS_PER_SECOND = 1000;
private static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
private static final int FASTEST_INTERVAL_IN_SECONDS = 1;
private static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
당신이 Activity
구현 GooglePlayServicesClient.ConnectionCallbacks
, GooglePlayServicesClient.OnConnectionFailedListener
및 LocationListener
.
public class LocationActivity extends Activity implements
GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {}
그런 다음을 설정 LocationClient
에 onCreate()
당신의 방법 Activity
:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocationClient = new LocationClient(this, this, this);
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
}
에 필요한 방법을 추가하십시오 Activity
. 연결될 onConnected()
때 호출되는 메서드입니다 LocationClient
. onLocationChanged()
가장 최신 위치를 검색 할 수있는 곳입니다.
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.w(TAG, "Location client connection failed");
}
@Override
public void onConnected(Bundle dataBundle) {
Log.d(TAG, "Location client connected");
mLocationClient.requestLocationUpdates(mLocationRequest, this);
}
@Override
public void onDisconnected() {
Log.d(TAG, "Location client disconnected");
}
@Override
public void onLocationChanged(Location location) {
if (location != null) {
Log.d(TAG, "Updated Location: " + Double.toString(location.getLatitude()) + "," + Double.toString(location.getLongitude()));
} else {
Log.d(TAG, "Updated location NULL");
}
}
꼭 LocationClient
필요한 경우에만 추가 배터리를 사용하고 GPS가 무한정 실행되지 않도록 연결 / 연결 해제하십시오 . 은 LocationClient
그것에서 데이터를 얻기 위해 연결해야합니다.
public void onResume() {
super.onResume();
mLocationClient.connect();
}
public void onStop() {
if (mLocationClient.isConnected()) {
mLocationClient.removeLocationUpdates(this);
}
mLocationClient.disconnect();
super.onStop();
}
사용자의 위치를 가져옵니다. 먼저 LocationClient
; 실패하면 LocationManager
.
public Location getLocation() {
if (mLocationClient != null && mLocationClient.isConnected()) {
return mLocationClient.getLastLocation();
} else {
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
if (locationManager != null) {
Location lastKnownLocationGPS = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastKnownLocationGPS != null) {
return lastKnownLocationGPS;
} else {
return locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
}
} else {
return null;
}
}
}
사용자에게 현재 위치를 제공하는 코드입니다.
Maps Activty 만들기 :
public class Maps extends MapActivity {
public static final String TAG = "MapActivity";
private MapView mapView;
private LocationManager locationManager;
Geocoder geocoder;
Location location;
LocationListener locationListener;
CountDownTimer locationtimer;
MapController mapController;
MapOverlay mapOverlay = new MapOverlay();
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
initComponents();
mapView.setBuiltInZoomControls(true);
mapView.setSatellite(true);
mapView.setTraffic(true);
mapView.setStreetView(true);
mapController = mapView.getController();
mapController.setZoom(16);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
if (locationManager == null) {
Toast.makeText(Maps.this, "Location Manager Not Available",
Toast.LENGTH_SHORT).show();
return;
}
location = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location == null)
location = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
double lat = location.getLatitude();
double lng = location.getLongitude();
Toast.makeText(Maps.this, "Location Are" + lat + ":" + lng,
Toast.LENGTH_SHORT).show();
GeoPoint point = new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6));
mapController.animateTo(point, new Message());
mapOverlay.setPointToDraw(point);
List<Overlay> listOfOverlays = mapView.getOverlays();
listOfOverlays.clear();
listOfOverlays.add(mapOverlay);
}
locationListener = new LocationListener() {
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {}
public void onProviderEnabled(String arg0) {}
public void onProviderDisabled(String arg0) {}
public void onLocationChanged(Location l) {
location = l;
locationManager.removeUpdates(this);
if (l.getLatitude() == 0 || l.getLongitude() == 0) {
} else {
double lat = l.getLatitude();
double lng = l.getLongitude();
Toast.makeText(Maps.this, "Location Are" + lat + ":" + lng,
Toast.LENGTH_SHORT).show();
}
}
};
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 1000, 10f, locationListener);
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 1000, 10f, locationListener);
locationtimer = new CountDownTimer(30000, 5000) {
@Override
public void onTick(long millisUntilFinished) {
if (location != null) locationtimer.cancel();
}
@Override
public void onFinish() {
if (location == null) {
}
}
};
locationtimer.start();
}
public MapView getMapView() {
return this.mapView;
}
private void initComponents() {
mapView = (MapView) findViewById(R.id.map_container);
ImageView ivhome = (ImageView) this.findViewById(R.id.imageView_home);
ivhome.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent(Maps.this, GridViewContainer.class);
startActivity(intent);
finish();
}
});
}
@Override
protected boolean isRouteDisplayed() {
return false;
}
class MapOverlay extends Overlay {
private GeoPoint pointToDraw;
public void setPointToDraw(GeoPoint point) {
pointToDraw = point;
}
public GeoPoint getPointToDraw() {
return pointToDraw;
}
@Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
long when) {
super.draw(canvas, mapView, shadow);
Point screenPts = new Point();
mapView.getProjection().toPixels(pointToDraw, screenPts);
Bitmap bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.select_map);
canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 24, null);
return true;
}
}
}
main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:orientation="vertical" >
<com.google.android.maps.MapView
android:id="@+id/map_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:apiKey="yor api key"
android:clickable="true"
android:focusable="true" />
</LinearLayout>
매니페스트에서 다음 권한을 정의하십시오.
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
대답은 이미 여기에 나와 있지만. 그런 시나리오를 접할 경우를 대비하여 이것을 전 세계에 공유하고 싶었습니다.
내 요구 사항은 최대 30 ~ 35 초 이내에 사용자의 현재 위치를 가져와야했기 때문에 Nirav Ranpara의 답변에 따라 만든 솔루션 입니다.
1. 모든 GPS 및 네트워크 항목을 처리하는 MyLocationManager.java 클래스를 만들었 습니다.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.app.callbacks.OnLocationDetectectionListener;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;
public class MyLocationManager {
/** The minimum distance to GPS change Updates in meters **/
private final long MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_GPS = 2; // 2
// meters
/** The minimum time between GPS updates in milliseconds **/
private final long MIN_TIME_BW_UPDATES_OF_GPS = 1000 * 5 * 1; // 5
// seconds
/** The minimum distance to NETWORK change Updates in meters **/
private final long MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_NETWORK = 5; // 5
// meters
/** The minimum time between NETWORK updates in milliseconds **/
private final long MIN_TIME_BW_UPDATES_OF_NETWORK = 1000 * 10 * 1; // 10
// seconds
/**
* Lets just say i don't trust the first location that the is found. This is
* to avoid that
**/
private int NetworkLocationCount = 0, GPSLocationCount = 0;
private boolean isGPSEnabled;
private boolean isNetworkEnabled;
/**
* Don't do anything if location is being updated by Network or by GPS
*/
private boolean isLocationManagerBusy;
private LocationManager locationManager;
private Location currentLocation;
private Context mContext;
private OnLocationDetectectionListener mListener;
public MyLocationManager(Context mContext,
OnLocationDetectectionListener mListener) {
this.mContext = mContext;
this.mListener = mListener;
}
/**
* Start the location manager to find my location
*/
public void startLocating() {
try {
locationManager = (LocationManager) mContext
.getSystemService(Context.LOCATION_SERVICE);
// Getting GPS status
isGPSEnabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
// Getting network status
isNetworkEnabled = locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnabled && !isNetworkEnabled) {
// No network provider is enabled
showSettingsAlertDialog();
} else {
// If GPS enabled, get latitude/longitude using GPS Services
if (isGPSEnabled) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES_OF_GPS,
MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_GPS,
gpsLocationListener);
}
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES_OF_NETWORK,
MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_NETWORK,
networkLocationListener);
}
}
/**
* My 30 seconds plan to get myself a location
*/
ScheduledExecutorService se = Executors
.newSingleThreadScheduledExecutor();
se.schedule(new Runnable() {
@Override
public void run() {
if (currentLocation == null) {
if (isGPSEnabled) {
currentLocation = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} else if (isNetworkEnabled) {
currentLocation = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
}
if (currentLocation != null && mListener != null) {
locationManager.removeUpdates(gpsLocationListener);
locationManager
.removeUpdates(networkLocationListener);
mListener.onLocationDetected(currentLocation);
}
}
}
}, 30, TimeUnit.SECONDS);
} catch (Exception e) {
Log.e("Error Fetching Location", e.getMessage());
Toast.makeText(mContext,
"Error Fetching Location" + e.getMessage(),
Toast.LENGTH_SHORT).show();
}
}
/**
* Handle GPS location listener callbacks
*/
private LocationListener gpsLocationListener = new LocationListener() {
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onLocationChanged(Location location) {
if (GPSLocationCount != 0 && !isLocationManagerBusy) {
Log.d("GPS Enabled", "GPS Enabled");
isLocationManagerBusy = true;
currentLocation = location;
locationManager.removeUpdates(gpsLocationListener);
locationManager.removeUpdates(networkLocationListener);
isLocationManagerBusy = false;
if (currentLocation != null && mListener != null) {
mListener.onLocationDetected(currentLocation);
}
}
GPSLocationCount++;
}
};
/**
* Handle Network location listener callbacks
*/
private LocationListener networkLocationListener = new LocationListener() {
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onLocationChanged(Location location) {
if (NetworkLocationCount != 0 && !isLocationManagerBusy) {
Log.d("Network", "Network");
isLocationManagerBusy = true;
currentLocation = location;
locationManager.removeUpdates(gpsLocationListener);
locationManager.removeUpdates(networkLocationListener);
isLocationManagerBusy = false;
if (currentLocation != null && mListener != null) {
mListener.onLocationDetected(currentLocation);
}
}
NetworkLocationCount++;
}
};
/**
* Function to show settings alert dialog. On pressing the Settings button
* it will launch Settings Options.
* */
public void showSettingsAlertDialog() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
// Setting Dialog Title
alertDialog.setTitle("GPS is settings");
// Setting Dialog Message
alertDialog
.setMessage("GPS is not enabled. Do you want to go to settings menu?");
// On pressing the Settings button.
alertDialog.setPositiveButton("Settings",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(
Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
}
});
// On pressing the cancel button
alertDialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
}
}
2. 호출 프래그먼트 또는 활동에 결과를 다시 전달하기 위해 인터페이스 (콜백) OnLocationDetectectionListener.java 를 만들었습니다.
import android.location.Location;
public interface OnLocationDetectectionListener {
public void onLocationDetected(Location mLocation);
}
3. 그런 다음 인터페이스 를 구현 하는 MainAppActivty.java Activity를 만들었 OnLocationDetectectionListener
으며 여기에 내 위치를받는 방법이 있습니다.
public class MainAppActivty extends Activity implements
OnLocationDetectectionListener {
private Location currentLocation;
private MyLocationManager mLocationManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_home);
super.onCreate(savedInstanceState);
mLocationManager = new MyLocationManager(this, this);
mLocationManager.startLocating();
}
@Override
public void onLocationDetected(Location mLocation) {
//Your new Location is received here
currentLocation = mLocation;
}
4. 매니페스트 파일에 다음 권한을 추가합니다.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
이것이 다른 사람들에게 도움이되기를 바랍니다. :)
사용자의 현재 위치를 확인하고 표시하려면을 사용할 수도 있습니다 MyLocationOverlay
. mapView
활동에 필드 가 있다고 가정합니다 . 사용자 위치를 표시하려면 다음 만 수행하면됩니다.
myLocationOverlay = new MyLocationOverlay(this, mapView);
myLocationOverlay.enableMyLocation();
mapView.getOverlays().add(myLocationOverlay);
이것은 GPS 또는 네트워크에서 현재 위치를 가져옵니다. 둘 다 실패하면 enableMyLocation()
을 반환 false
합니다.
주변 사물의 위치에 관해서 ItemizedOverlay
는이 트릭을해야합니다.
나는 당신의 질문을 오해하지 않았기를 바랍니다. 행운을 빕니다.
수정 : Google Play 서비스 라이브러리 의 최신 위치 서비스 API로 업데이트 됨 (2014 년 7 월)
위치 제공 업체 선택 및 전원 관리와 같은 작업을 자동화하는보다 강력하고 높은 수준의 프레임 워크를 제공하는 Google Play 서비스 라이브러리에서 사용할 수 있는 새로운 위치 서비스 API 를 사용하는 것이 좋습니다 . 공식 문서에 따르면 "... Location API를 사용하면 기본 위치 기술의 세부 사항에 집중할 필요없이 위치 인식 응용 프로그램을 쉽게 구축 할 수 있습니다. 또한 모든 기능을 사용하여 전력 소비를 최소화 할 수 있습니다. 장치 하드웨어의. "
자세한 내용은 다음 사이트를 방문하십시오 : 앱 위치 인식 만들기
최신 위치 서비스 API를 사용하는 전체 예제를 보려면 다음을 방문하십시오. Android LocationClient 클래스는 더 이상 사용되지 않지만 문서에서 사용됩니다.
지난 1 년 동안 GPS_PROVIDER와 NETWORK_PROVIDER의 조합을 사용하여 현재 위치를 가져 왔고 잘 작동했지만 지난 몇 달 동안 오랫동안 지연된 후 위치를 가져 와서 최신 API FusedLocationProviderClient로 전환했습니다. 꽤 잘 작동합니다.
다음은 FusedLocationProviderClient를 사용하여 현재 위치를 가져 오기 위해 작성한 클래스입니다. 아래 코드에서는 타이머를 사용하여 현재 위치를 얻기 위해 기다리는 동안 타이머를 15 초 지연 예약했습니다. 사용자에 따라 변경할 수 있습니다.
private static FusedLocationService ourInstance;
private final LocationRequest locationRequest;
private FusedLocationProviderClient mFusedLocationClient;
private Location mLastLocation;
private Context context;
private FindOutLocation findOutLocation;
private boolean callbackTriggered = false;
private Timer timer;
public static FusedLocationService getInstance(Context pContext) {
if (null == ourInstance) ourInstance = new FusedLocationService(pContext);
return ourInstance;
}
private FusedLocationService(Context pContext) {
context = pContext;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
locationRequest = getLocationRequest();
requestLocation(context);
}
public Location getLastKnownLocation() {
return mLastLocation;
}
private void requestLocation(Context context) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mFusedLocationClient.requestLocationUpdates(locationRequest, mLocationCallback, null);
mFusedLocationClient.getLastLocation().addOnSuccessListener(location -> {
if (location != null) {
mLastLocation = location;
triggerCallback(mLastLocation);
}
});
}
private LocationRequest getLocationRequest() {
LocationRequest locationRequest = new LocationRequest();
long INTERVAL = 10 * 1000;
long FASTEST_INTERVAL = 5 * 1000;
locationRequest.setInterval(INTERVAL);
locationRequest.setFastestInterval(FASTEST_INTERVAL);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
return locationRequest;
}
private LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
for (Location location : locationResult.getLocations()) {
if (location != null) mLastLocation = location;
}
if (null != mLastLocation) triggerCallback(mLastLocation);
}
};
public static abstract class FindOutLocation {
public abstract void gotLocation(Location location);
}
@SuppressLint("MissingPermission")
public void findLocation(FindOutLocation findOutLocation) {
long TIMER_TIME_OUT = 15 * 1000;
this.findOutLocation = findOutLocation;
callbackTriggered = false;
try {
requestLocation(context);
timer = new Timer();
timer.schedule(new GetLastLocation(context), TIMER_TIME_OUT);
} catch (Exception e) {
e.printStackTrace();
}
}
private class GetLastLocation extends TimerTask {
Context context;
GetLastLocation(Context context) {
this.context = context;
}
@Override
public void run() {
triggerCallback(mLastLocation);
}
}
private void triggerCallback(Location location) {
if (null != location) mLastLocation = location;
if (!callbackTriggered && null != findOutLocation) {
callbackTriggered = true;
removeLocationUpdates();
findOutLocation.gotLocation(location);
findOutLocation = null;
}
}
private void removeLocationUpdates() {
if (null != timer) timer.cancel();
if (null != mFusedLocationClient)
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
}
}
그리고 이것을 활동에서 호출했습니다. 여기에 코드가 있습니다.
FusedLocationService.FindOutLocation findOutLocation = new FusedLocationService.FindOutLocation() {
@Override
public void gotLocation(Location currentLocation) {
if (currentLocation != null) {
/*TODO DO SOMETHING WITH CURRENT LOCATION*/
}
}
};
FusedLocationService.getInstance(this).findLocation(findOutLocation);
AndroidManifest.xml에 다음 항목을 추가하십시오.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />
public static Location getBestLocation(Context ctxt) {
Location gpslocation = getLocationByProvider(
LocationManager.GPS_PROVIDER, ctxt);
Location networkLocation = getLocationByProvider(
LocationManager.NETWORK_PROVIDER, ctxt);
Location fetchedlocation = null;
// if we have only one location available, the choice is easy
if (gpslocation != null) {
Log.i("New Location Receiver", "GPS Location available.");
fetchedlocation = gpslocation;
} else {
Log.i("New Location Receiver",
"No GPS Location available. Fetching Network location lat="
+ networkLocation.getLatitude() + " lon ="
+ networkLocation.getLongitude());
fetchedlocation = networkLocation;
}
return fetchedlocation;
}
/**
* get the last known location from a specific provider (network/gps)
*/
private static Location getLocationByProvider(String provider, Context ctxt) {
Location location = null;
// if (!isProviderSupported(provider)) {
// return null;
// }
LocationManager locationManager = (LocationManager) ctxt
.getSystemService(Context.LOCATION_SERVICE);
try {
if (locationManager.isProviderEnabled(provider)) {
location = locationManager.getLastKnownLocation(provider);
}
} catch (IllegalArgumentException e) {
Log.i("New Location Receiver", "Cannot access Provider " + provider);
}
return location;
}
GeoLocation을위한 간단하고 최상의 방법입니다.
LocationManager lm = null;
boolean network_enabled;
if (lm == null)
lm = (LocationManager) Kikit.this.getSystemService(Context.LOCATION_SERVICE);
network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
dialog = ProgressDialog.show(Kikit.this, "", "Fetching location...", true);
final Handler handler = new Handler();
timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run()
{
Log.e("counter value","value "+counter);
if(counter<=8)
{
try
{
counter++;
if (network_enabled) {
lm = (LocationManager) Kikit.this.getSystemService(Context.LOCATION_SERVICE);
Log.e("in network_enabled..","in network_enabled");
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener()
{
public void onLocationChanged(Location location)
{
if(attempt == false)
{
attempt = true;
Log.e("in location listener..","in location listener..");
longi = location.getLongitude();
lati = location.getLatitude();
Data.longi = "" + longi;
Data.lati = "" + lati;
Log.e("longitude : ",""+longi);
Log.e("latitude : ",""+lati);
if(faceboo_name.equals(""))
{
if(dialog!=null){
dialog.cancel();}
timer.cancel();
timer.purge();
Data.homepage_resume = true;
lm = null;
Intent intent = new Intent();
intent.setClass(Kikit.this,MainActivity.class);
startActivity(intent);
finish();
}
else
{
isInternetPresent = cd.isConnectingToInternet();
if (isInternetPresent)
{
if(dialog!=null)
dialog.cancel();
Showdata();
}
else
{
error_view.setText(Data.internet_error_msg);
error_view.setVisibility(0);
error_gone();
}
}
}
}
public void onStatusChanged(String provider, int status,
Bundle extras) {
}
public void onProviderEnabled(String provider) {
//Toast.makeText(getApplicationContext(), "Location enabled", Toast.LENGTH_LONG).show();
}
public void onProviderDisabled(String provider) {
}
};
// Register the listener with the Location Manager to receive
// location updates
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 100000, 10,locationListener);
} else{
//Toast.makeText(getApplicationContext(), "No Internet Connection.", 2000).show();
buildAlertMessageNoGps();
}
} catch (Exception e) {
// TODO
// Auto-generated
// catch
// block
}
}
else
{
timer.purge();
timer.cancel();
if(attempt == false)
{
attempt = true;
String locationProvider = LocationManager.NETWORK_PROVIDER;
// Or use LocationManager.GPS_PROVIDER
try {
Location lastKnownLocation = lm.getLastKnownLocation(locationProvider);
longi = lastKnownLocation.getLongitude();
lati = lastKnownLocation.getLatitude();
Data.longi = "" + longi;
Data.lati = "" + lati;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.i("exception in loc fetch", e.toString());
}
Log.e("longitude of last known location : ",""+longi);
Log.e("latitude of last known location : ",""+lati);
if(Data.fb_access_token == "")
{
if(dialog!=null){
dialog.cancel();}
timer.cancel();
timer.purge();
Data.homepage_resume = true;
Intent intent = new Intent();
intent.setClass(Kikit.this,MainActivity.class);
startActivity(intent);
finish();
}
else
{
isInternetPresent = cd.isConnectingToInternet();
if (isInternetPresent)
{
if(dialog!=null){
dialog.cancel();}
Showdata();
}
else
{
error_view.setText(Data.internet_error_msg);
error_view.setVisibility(0);
error_gone();
}
}
}
}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 2000);
private void buildAlertMessageNoGps() {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Your WiFi & mobile network location is disabled , do you want to enable it?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(@SuppressWarnings("unused") final DialogInterface dialog, @SuppressWarnings("unused") final int id)
{
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
setting_page = true;
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, @SuppressWarnings("unused") final int id) {
dialog.cancel();
finish();
}
});
final AlertDialog alert = builder.create();
alert.show();
}
여기에 조금 늦었지만 그런 상황에서 내가 할 일은 Google Maps API를 사용하고 Google지도의 위도 및 경도 API를 사용하여 주변 위치를 표시하는 것입니다. 또한지도에 위치를 표시 할 수 있다면 사용자 경험이 더 좋습니다. 사용자 위치 업데이트에 대해 신경 쓰거나 Android API를 사용할 필요가 없습니다. Google지도가 내부를 처리하도록합니다.
@emmby가 자신의 앱에서 문제를 해결했을 수도 있지만 향후 참조를 위해 Google지도 API에서 위치 별 항목을 살펴 보는 것이 동료 개발자에게 추천하는 것입니다.
편집 : Google지도에서 사용자 위치 를 표시하기위한 링크
Android에서 위치 업데이트를 얻으려면 많은 것들이 필요하고 많은 bolierplate 코드가 필요합니다.
당신은 돌봐야합니다
- Google Play 서비스 가용성 확인,
- Google Play 서비스가 오래되었거나 사용할 수없는 경우 업데이트
- GoogleApiClient 및 해당 콜백 연결, 연결 해제 등의 대화 생성
- 위치 업데이트를위한 리소스 중지 및 해제
- 위치 권한 시나리오 처리
- 위치 서비스가 켜져 있는지 또는 꺼져 있는지 확인
- lastknown 위치를 얻는 것도 쉽지 않습니다.
- 특정 기간 후에도 위치를 얻지 못하면 마지막으로 알려진 위치로 대체
이 모든 것을 처리하고 비즈니스 로직에 집중할 수있는 Android-EasyLocation (작은 Android 라이브러리) 을 만들었습니다 .
당신이 필요로하는 확장이다 EasyLocationActivity 이를
requestSingleLocationFix(easyLocationRequest);
또는
requestLocationUpdates(easyLocationRequest);
https://github.com/akhgupta/Android-EasyLocation 에서 필요한 샘플 앱 및 단계를 확인하세요.
이것이 내가 사용자 권한을 요청하는 방법입니다.
AndroidManifest.xml의 애플리케이션 태그 외부에 이러한 권한 요청을 추가합니다.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
그런 다음 App Gradle 파일에 Google의 위치 종속성을 추가합니다.
implementation 'com.google.android.gms:play-services-location:15.0.0'
이제 일부 전역 변수를 선언하십시오.
private lateinit var mFusedLocationProvider:FusedLocationProviderClient
private lateinit var mLocationCallback: LocationCallback
private lateinit var mLocationRequest: LocationRequest
private var mLocationPermissionGranted:Boolean = false
귀하의 활동의 OnCreate 메서드에서 (코드를 올바르게 형식화 할 수 없었습니다. 사과드립니다)
mFusedLocationProvider = LocationServices.getFusedLocationProviderClient(this)
//Location Callback
mLocationCallback = object: LocationCallback(){
override fun onLocationResult(p0: LocationResult?) {
if(p0==null){
//todo(request user to enable location from settings then remove return)
return
}else{
getDeviceLocation()
}
}
}
//Location Request
mLocationRequest = LocationRequest.create()
mLocationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
//Set the Interval for Latest Interval Update
mLocationRequest.interval = 5000
//Set How Many Location Updated you Want
mLocationRequest.numUpdates = 1
getLocationPermission()
getDeviceLocation()
이제 두 함수를 모두 만듭니다.
private fun getLocationPermission() {
val permission:Array<String> = arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION,android.Manifest.permission.ACCESS_COARSE_LOCATION)
if(ContextCompat.checkSelfPermission(applicationContext,Constant.FINE_LOCATION)== PermissionChecker.PERMISSION_GRANTED){
if(ContextCompat.checkSelfPermission(applicationContext,Constant.COARSE_LOCATION)== PermissionChecker.PERMISSION_GRANTED){
mLocationPermissionGranted = true
}
}else{
ActivityCompat.requestPermissions(this,permission,Constant.LOCATION_REQUEST_CODE)
}
}
두 번째 방법
private fun getDeviceLocation() {
try{
if(mLocationPermissionGranted){
mFusedLocationProvider.lastLocation.addOnCompleteListener(this,{task: Task<Location> ->
if(task.isSuccessful){
var currentLocation: Location? = task.result
if(currentLocation!=null){
Log.i("Location","Latitude is ${currentLocation.latitude} and Longitude" +
"${currentLocation.longitude}")
}
else
mFusedLocationProvider.requestLocationUpdates(mLocationRequest,mLocationCallback,null)
}
})
}
}catch (e:SecurityException){
Log.e("Error", "Security Exception ${e.message}")
}
}
Constant.kt의 경우
class Constant{
companion object {
//Location Request Settings
const val SET_INTERVAL:Long = 2000
const val NUM_UPDATES:Int = 1
//Location Permission
const val FINE_LOCATION:String = android.Manifest.permission.ACCESS_FINE_LOCATION
const val COARSE_LOCATION:String = android.Manifest.permission.ACCESS_COARSE_LOCATION
}
}
@Fedor Greate 답변 의 Kotlin 버전 :
수업 사용 :
val locationResult = object : MyLocation.LocationResult() {
override fun gotLocation(location: Location?) {
val lat = location!!.latitude
val lon = location.longitude
Toast.makeText(context, "$lat --SLocRes-- $lon", Toast.LENGTH_SHORT).show()
}
}
val myLocation = MyLocation()
myLocation.getLocation(inflater.context, locationResult)
MyLocation
수업 :
class MyLocation {
internal lateinit var timer1: Timer
internal var lm: LocationManager? = null
internal lateinit var locationResult: LocationResult
internal var gps_enabled = false
internal var network_enabled = false
internal var locationListenerGps: LocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
timer1.cancel()
locationResult.gotLocation(location)
lm!!.removeUpdates(this)
lm!!.removeUpdates(locationListenerNetwork)
}
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
}
internal var locationListenerNetwork: LocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
timer1.cancel()
locationResult.gotLocation(location)
lm!!.removeUpdates(this)
lm!!.removeUpdates(locationListenerGps)
}
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
}
fun getLocation(context: Context, result: LocationResult): Boolean {
//I use LocationResult callback class to pass location value from MyLocation to user code.
locationResult = result
if (lm == null)
lm = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
//exceptions will be thrown if provider is not permitted.
try {
gps_enabled = lm!!.isProviderEnabled(LocationManager.GPS_PROVIDER)
} catch (ex: Exception) {
}
try {
network_enabled = lm!!.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
} catch (ex: Exception) {
}
//don't start listeners if no provider is enabled
if (!gps_enabled && !network_enabled)
return false
if (ActivityCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) run {
ActivityCompat.requestPermissions(context as Activity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION), 111)
}
if (gps_enabled)
lm!!.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, locationListenerGps)
if (network_enabled)
lm!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0f, locationListenerNetwork)
timer1 = Timer()
timer1.schedule(GetLastLocation(context), 20000)
return true
}
internal inner class GetLastLocation(var context: Context) : TimerTask() {
override fun run() {
lm!!.removeUpdates(locationListenerGps)
lm!!.removeUpdates(locationListenerNetwork)
var net_loc: Location? = null
var gps_loc: Location? = null
if (ActivityCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
) run {
ActivityCompat.requestPermissions(context as Activity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION),111)
}
if (gps_enabled)
gps_loc = lm!!.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if (network_enabled)
net_loc = lm!!.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
//if there are both values use the latest one
if (gps_loc != null && net_loc != null) {
if (gps_loc.getTime() > net_loc.getTime())
locationResult.gotLocation(gps_loc)
else
locationResult.gotLocation(net_loc)
return
}
if (gps_loc != null) {
locationResult.gotLocation(gps_loc)
return
}
if (net_loc != null) {
locationResult.gotLocation(net_loc)
return
}
locationResult.gotLocation(null)
}
}
abstract class LocationResult {
abstract fun gotLocation(location: Location?)
}
}
최신 API 인 FusedLocationProviderApi를 사용하여 Android에서 위치를 파악할 수있는 가능성 중에서 가장 좋습니다. 이것을 build.gradle 파일에 추가하십시오.
dependencies {
compile 'com.google.android.gms:play-services:6.5.87'
}
이 URL http://javapapers.com/android/android-location-fused-provider/로 전체 소스 코드를 얻을 수 있습니다.
내가하는 일은 다음과 같습니다.
- 우선 NETWORK 또는 GPS 제공 업체가 활성화되어 있는지 확인합니다. 일부는 장치에서 비활성화되고 일부는 응용 프로그램 매니페스트에서 비활성화 될 수 있습니다. 공급자가 활성화 된 경우이 공급자에 대해 캐시 된 마지막 위치를 가져오고이 공급자에 대한 위치 업데이트 리스너를 시작합니다.
- 링크에 언급 된대로 위치가 마지막으로받은 위치보다 나은지 여부를 확인하는 방법이 있습니다 .- https://developer.android.com/guide/topics/location/strategies.html#BestEstimate
- 위치 수신기에서 업데이트를 받으면이 위치가 이전에받은 위치보다 나은지 확인합니다. 이 위치를 이전 최적 위치 (
mFinalLocation
) 로 바꾸는 것보다 낫다면 . - 또한 2 분 동안 핸들러 (타이머)가있어 결국 서비스를 중지하고 서비스
onDestroy()
방법에서 각 공급자에 대한 위치 업데이트 수신을 중지합니다.
아래는 서비스 코드입니다. 필요한 위치 업데이트 빈도에 따라 실행할 수 있습니다.
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.Log;
public class RecordLocationService extends Service {
private final String TAG = RecordLocationService.class.getSimpleName();
private final int TWO_MINUTES = 1000 * 60 * 2;
private LocationManager mLocationManager;
private MyLocationListener mLocationListeners[] = new MyLocationListener[]{
new MyLocationListener(LocationManager.NETWORK_PROVIDER),
new MyLocationListener(LocationManager.GPS_PROVIDER)
};
private Location mFinalLocation;
private class MyLocationListener implements LocationListener {
private String mProvider;
public MyLocationListener(String provider) {
Log.d(TAG, "LocationListener : " + provider);
mProvider = provider;
}
public String getProvider() {
return mProvider;
}
@Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged : " + location);
if (isBetterLocation(location, mFinalLocation)) {
Log.d(TAG, "Setting current Final Location to recent most Location for Provider : " + location.getProvider());
Log.d(TAG, "Setting current Final Location to : " + location);
mFinalLocation = location;
} else {
Log.d(TAG, "Keeping current Final Location to previous Final Location");
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.d(TAG, "onStatusChanged provider " + provider);
}
@Override
public void onProviderEnabled(String provider) {
Log.d(TAG, "onProviderEnabled provider " + provider);
}
@Override
public void onProviderDisabled(String provider) {
Log.d(TAG, "onProviderDisabled provider " + provider);
}
}
private Handler mStopServiceHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1: {
stopSelf();
}
break;
}
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Log.d(TAG, "onStartCommand");
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
requestLocation();
mStopServiceHandler.sendEmptyMessageDelayed(1, TWO_MINUTES);
}
private void requestLocation() {
// Acquire a reference to the system Location Manager
if (mLocationManager == null) {
mLocationManager = (LocationManager) this.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
try {
if (mLocationManager.getAllProviders().contains(LocationManager.NETWORK_PROVIDER) && mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.d(TAG, "Fetching Cached Location for Provider : " + LocationManager.NETWORK_PROVIDER);
Location cachedNetworkLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (cachedNetworkLocation != null) {
Log.d(TAG, "Setting Final Location to Cached Location for Provider : " + LocationManager.NETWORK_PROVIDER);
Log.d(TAG, "Setting Final Location to : " + cachedNetworkLocation);
mFinalLocation = cachedNetworkLocation;
} else {
Log.d(TAG, "Cached Location for Provider : " + LocationManager.NETWORK_PROVIDER + " is NULL");
}
Log.d(TAG, "Requesting Location Update for Provider : " + LocationManager.NETWORK_PROVIDER);
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, mLocationListeners[0]);
}
} catch (SecurityException se) {
Log.e(TAG, se.getMessage(), se);
} catch (IllegalArgumentException iae) {
Log.e(TAG, iae.getMessage(), iae);
}
try {
if (mLocationManager.getAllProviders().contains(LocationManager.GPS_PROVIDER) && mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Log.d(TAG, "Fetching Cached Location for Provider : " + LocationManager.GPS_PROVIDER);
Location cachedGPSLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (cachedGPSLocation != null) {
if (isBetterLocation(cachedGPSLocation, mFinalLocation)) {
Log.d(TAG, "Setting Final Location to Cached Location for Provider : " + LocationManager.GPS_PROVIDER);
Log.d(TAG, "Setting Final Location to : " + cachedGPSLocation);
mFinalLocation = cachedGPSLocation;
}
} else {
Log.d(TAG, "Cached Location for Provider : " + LocationManager.GPS_PROVIDER + " is NULL");
}
Log.d(TAG, "Requesting Location Update for Provider : " + LocationManager.GPS_PROVIDER);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mLocationListeners[1]);
}
} catch (SecurityException se) {
Log.e(TAG, se.getMessage(), se);
} catch (IllegalArgumentException iae) {
Log.e(TAG, iae.getMessage(), iae);
}
}
/**
* Determines whether one Location reading is better than the current Location fix
*
* @param location The new Location that you want to evaluate
* @param currentBestLocation The current Location fix, to which you want to compare the new one
*/
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
}
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be worse
} else if (isSignificantlyOlder) {
return false;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return true;
}
return false;
}
/**
* Checks whether two providers are the same
*/
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
if (mLocationManager != null) {
for (int i = 0; i < mLocationListeners.length; i++) {
try {
Log.d(TAG, "Removing Location Update for Provider : " + mLocationListeners[i].getProvider());
mLocationManager.removeUpdates(mLocationListeners[i]);
} catch (Exception ex) {
Log.e(TAG, "fail to remove location listeners, ignore", ex);
}
}
}
}
}
최근 코드의 위치를 파악하고 좋은 아이디어를 배우고 마침내 비교적 완벽한 라이브러리와 데모를 얻기 위해 리팩토링되었습니다.
//request all valid provider(network/gps)
private boolean requestAllProviderUpdates() {
checkRuntimeEnvironment();
checkPermission();
if (isRequesting) {
EasyLog.d("Request location update is busy");
return false;
}
long minTime = getCheckTimeInterval();
float minDistance = getCheckMinDistance();
if (mMapLocationListeners == null) {
mMapLocationListeners = new HashMap<>();
}
mValidProviders = getValidProviders();
if (mValidProviders == null || mValidProviders.isEmpty()) {
throw new IllegalArgumentException("Not available provider.");
}
for (String provider : mValidProviders) {
LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if (location == null) {
EasyLog.e("LocationListener callback location is null.");
return;
}
printf(location);
mLastProviderTimestamp = location.getTime();
if (location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
finishResult(location);
} else {
doLocationResult(location);
}
removeProvider(location.getProvider());
if (isEmptyValidProviders()) {
requestTimeoutMsgInit();
removeUpdates();
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
};
getLocationManager().requestLocationUpdates(provider, minTime, minDistance, locationListener);
mMapLocationListeners.put(provider, locationListener);
EasyLog.d("Location request %s provider update.", provider);
}
isRequesting = true;
return true;
}
//remove request update
public void removeUpdates() {
checkRuntimeEnvironment();
LocationManager locationManager = getLocationManager();
if (mMapLocationListeners != null) {
Set<String> keys = mMapLocationListeners.keySet();
for (String key : keys) {
LocationListener locationListener = mMapLocationListeners.get(key);
if (locationListener != null) {
locationManager.removeUpdates(locationListener);
EasyLog.d("Remove location update, provider is " + key);
}
}
mMapLocationListeners.clear();
isRequesting = false;
}
}
//Compared with the last successful position, to determine whether you need to filter
private boolean isNeedFilter(Location location) {
checkLocation(location);
if (mLastLocation != null) {
float distance = location.distanceTo(mLastLocation);
if (distance < getCheckMinDistance()) {
return true;
}
if (location.getAccuracy() >= mLastLocation.getAccuracy()
&& distance < location.getAccuracy()) {
return true;
}
if (location.getTime() <= mLastProviderTimestamp) {
return true;
}
}
return false;
}
private void doLocationResult(Location location) {
checkLocation(location);
if (isNeedFilter(location)) {
EasyLog.d("location need to filtered out, timestamp is " + location.getTime());
finishResult(mLastLocation);
} else {
finishResult(location);
}
}
//Return to the finished position
private void finishResult(Location location) {
checkLocation(location);
double latitude = location.getLatitude();
double longitude = location.getLongitude();
float accuracy = location.getAccuracy();
long time = location.getTime();
String provider = location.getProvider();
if (mLocationResultListeners != null && !mLocationResultListeners.isEmpty()) {
String format = "Location result:<%f, %f> Accuracy:%f Time:%d Provider:%s";
EasyLog.i(String.format(format, latitude, longitude, accuracy, time, provider));
mLastLocation = location;
synchronized (this) {
Iterator<LocationResultListener> iterator = mLocationResultListeners.iterator();
while (iterator.hasNext()) {
LocationResultListener listener = iterator.next();
if (listener != null) {
listener.onResult(location);
}
iterator.remove();
}
}
}
}
* 위치를 완료하기위한 각 요청은 업데이트를 제거하는 것이 가장 좋습니다. 그렇지 않으면 전화 상태 표시 줄에 항상 위치 아이콘이 표시됩니다.
After seeing all the answers, and question (Simplest and Robust). I got clicked about only library Android-ReactiveLocation.
When i made an location tracking app. Then i realized that its very typical to handle location tracking with optimised with battery.
So i want tell freshers and also developers who don't want to maintain their location code with future optimisations. Use this library.
ReactiveLocationProvider locationProvider = new
ReactiveLocationProvider(context);
locationProvider.getLastKnownLocation()
.subscribe(new Consumer<Location>() {
@Override
public void call(Location location) {
doSthImportantWithObtainedLocation(location);
}
});
Dependencies to put in app level build.gradle
dependencies {
...
compile 'pl.charmas.android:android-reactive-location2:2.1@aar'
compile 'com.google.android.gms:play-services-location:11.0.4' //you can use newer GMS version if you need
compile 'com.google.android.gms:play-services-places:11.0.4'
compile 'io.reactivex:rxjava:2.0.5' //you can override RxJava version if you need
}
Pros to use this lib:
- This lib is and will be actively maintained.
- You dont worry about battery optimisation. As developers have done their best.
- Easy installation, put dependency and play.
- easily connect to Play Services API
- obtain last known location
- subscribe for location updates use
- location settings API
- manage geofences
- geocode location to list of addresses
- activity recognition
- use current place API fetch place
- autocomplete suggestions
Before I answer, I just want to be upfront about the fact that I’m affiliated with Neura. Now to your question. So, instead of wasting your time behind coding to get your user’s location, you can use our SDK. It takes less than 30 mins to integrate. Neura provides you with your user’s location/activity,and you can configure your application accordingly to perform certain tasks after you receive the data. Here’s a few reasons to use Neura over other Activity recognition API’s:
- No need to code tons of lines to understand your user.
- Gives you accurate results.
- Consumes less than 1% of your battery.
'code' 카테고리의 다른 글
GitHub에서 직접 npm 패키지를 설치하는 방법은 무엇입니까? (0) | 2020.09.29 |
---|---|
Java에서 메소드 실행 시간을 어떻게 측정합니까? (0) | 2020.09.29 |
PostgreSQL 데이터베이스의 모든 테이블을 삭제하려면 어떻게해야합니까? (0) | 2020.09.28 |
PowerShell에서 코드를 어떻게 주석 처리합니까? (0) | 2020.09.28 |
병합을 완료하지 않았습니다 (MERGE_HEAD가 있음). (0) | 2020.09.28 |