彭方文 發表於 2025-11-5 09:45:11

Android实现获取定位信息的工具类

<p>相信大家在项目中应该会经常用到这类功能,需要在请求api的时候获取当前定位信息,以便获取周边信息,以下是我常用的工具类,大家应该用得上</p>
<div class="jb51code"><pre class="brush:java;">import android.annotation.SuppressLint;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.Handler;
import android.os.Looper;

import androidx.annotation.NonNull;


/**
* 描述: 获取定位信息
* 创建者: IT乐手
* 日期: 2025/5/21
*/

public class LocationUtils {

    private final static String TAG = "LocationUtils";

    private static double latitude = 22.665424;
    private static double longitude = 114.075724;

    private static LocationManager locationManager = null;
    private static final Handler mainHandler = new Handler(Looper.getMainLooper());

    /**
   * 获取经纬度
   * @return 经纬度字符串
   */
    public static String getLocationString() {
      double[] locations = getLocation();
      String locationStr = locations+","+locations;
      AtotoLogger.d(TAG, locationStr);
      return locationStr;
    }

    @SuppressLint("MissingPermission")
    public static double[] getLocation() {
      if (locationManager == null) {
            locationManager = (LocationManager) AppGlobalUtils.getApplication().getSystemService(Context.LOCATION_SERVICE);
      }
      // 检查GPS/网络是否可用
      boolean hasGps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
      boolean hasNetwork = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
      boolean hasPassive = locationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER);
      AtotoLogger.d(TAG, "hasGps = " + hasGps + ", hasNetwork = " + hasNetwork + ", hasPassive = " + hasPassive);
      if (!hasGps &amp;&amp; !hasNetwork) {
            AtotoLogger.e(TAG, "Gps and Network are not available");
            return new double[]{0,0};
      }

      Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

      if (location == null) {
            AtotoLogger.d(TAG, "GPS location is null, trying Network location");
            location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
      }

      if (location == null) {
            AtotoLogger.e(TAG, "Location is null");
            // 在主线程中请求位置更新
            if (Looper.myLooper() == Looper.getMainLooper()) {
                requestLocationUpdatesOnCurrentThread();
            } else {
                mainHandler.post(LocationUtils::requestLocationUpdatesOnCurrentThread);
            }
            return new double[]{latitude,longitude};
      }

      latitude = location.getLatitude();
      longitude = location.getLongitude();
      AtotoLogger.d(TAG, "Latitude: " + latitude + ", Longitude: " + longitude);
      // 处理经纬度信息
      return new double[]{latitude, longitude};
    }

    @SuppressLint("MissingPermission")
    private static void requestLocationUpdatesOnCurrentThread() {
      try {
            locationManager.requestLocationUpdates(
                  LocationManager.PASSIVE_PROVIDER,
                  0, // minTime (milliseconds)
                  0,   // minDistance (meters)
                  locationListener
            );
      } catch (Exception e) {
            AtotoLogger.e(TAG, "Request location updates failed: " + e.getMessage());
      }
    }

    private static final android.location.LocationListener locationListener = new android.location.LocationListener() {
      @Override
      public void onLocationChanged(Location location) {
            latitude = location.getLatitude();
            longitude = location.getLongitude();
            AtotoLogger.d(TAG, "Location updated: Latitude: " + latitude + ", Longitude: " + longitude);

            // 获取到位置后移除监听,避免持续更新
            removeLocationUpdates();
      }

      @Override
      public void onStatusChanged(String provider, int status, android.os.Bundle extras) {
      }

      @Override
      public void onProviderEnabled(@NonNull String provider) {
      }

      @Override
      public void onProviderDisabled(@NonNull String provider) {
      }
    };

    /**
   * 移除位置更新监听
   */
    public static void removeLocationUpdates() {
      if (locationManager != null) {
            try {
                locationManager.removeUpdates(locationListener);
            } catch (Exception e) {
                AtotoLogger.e(TAG, "Remove location updates failed: " + e.getMessage());
            }
      }
    }


    @SuppressLint("MissingPermission")
    private static Location getLastKnownLocation() {
      if (locationManager == null) return null;

      Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
      if (location == null) {
            location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
      }
      return location;
    }
}
</pre></div>
<p><strong>方法补充</strong></p>
<p><strong>Android 获取位置信息</strong></p>
<p>Android 提供 <code>LocationManager</code> 等相关API用于获取位置信息。</p>
<p><strong>1.权限申请</strong></p>
<p>APP申请定位权限</p>
<p>Manifest 文件中添加以下权限:</p>
<div class="jb51code"><pre class="brush:xml;">    &lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/&gt;
    &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/&gt;
</pre></div>
<ul><li>ACCESS_COARSE_LOCATION: 允许一个程序访问CellID或WiFi热点来获取粗略的位置</li><li>ACCESS_FINE_LOCATION: 允许一个程序访问精良位置(如GPS)</li></ul>
<p>开启手机定位服务</p>
<p>只有位置权限是不够的,还需要开启手机定位服务才能获取到位置信息。</p>
<div class="jb51code"><pre class="brush:java;">/**
   * 判断是否开启了GPS或网络定位开关
   */
public boolean isLocationProviderEnabled() {
    boolean result = false;
    LocationManager locationManager = (LocationManager) SDWanVPNApplication.getAppContext()
      .getSystemService(LOCATION_SERVICE);
    if (locationManager == null) {
      return false;
    }
    if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager
      .isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
      result = true;
    }
    return result;
}

/**
* 跳转到设置界面,引导用户开启定位服务
*/
private void openLocationServer() {
        Intent i = new Intent();
    i.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
    startActivityForResult(i, REQUEST_CODE_LOCATION_SERVER);
}

</pre></div>
<p><strong>2.监听位置信息</strong></p>
<p>Android 可以通过网络或者GPS,获取位置信息。GPS获取比较准确,但是在室内有时候比较难获取到。</p>
<div class="jb51code"><pre class="brush:java;">private final LocationListener mLocationListener = new LocationListener() {

    // Provider的状态在可用、暂时不可用和无服务三个状态直接切换时触发此函数
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
      Log.d(TAG, "onStatusChanged");
    }

    // Provider被enable时触发此函数,比如GPS被打开
    @Override
    public void onProviderEnabled(String provider) {
      Log.d(TAG, "onProviderEnabled");

    }

    // Provider被disable时触发此函数,比如GPS被关闭
    @Override
    public void onProviderDisabled(String provider) {
      Log.d(TAG, "onProviderDisabled");

    }

    //当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发
    @Override
    public void onLocationChanged(Location location) {
      Log.d(TAG, String.format("location: longitude: %f, latitude: %f", location.getLongitude(),
          location.getLatitude()));
      //更新位置信息
    }
};

/**
   * 监听位置变化
   */
private void initLocationListener() {
    LocationManager locationManager = (LocationManager) MyApplication.getAppContext()
      .getSystemService(LOCATION_SERVICE);
    if (locationManager == null) {
      return;
    }
   
    locationManager
      .requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 10, mLocationListener);
    locationManager
      .requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 10, mLocationListener);

}
</pre></div>
<p>其中最重要的就是 <code>requestLocationUpdates</code> 方法,使用指定的提供程序注册位置信息:</p>
<p>requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener) provider:注册的位置提供者名称 minTime:位置更新之间的最小时间间隔,以毫秒为单位 minDistance:位置更新之间的最小距离,以米为单位 listener:位置更新回调方法</p>
<p>该方法内部是通过<code>handler</code>进行通知回调,如果在非主线程调用该方法,需要多传入一个<code>Looper</code>参数:</p>
<div class="jb51code"><pre class="brush:java;">    Looper.prepare();
    locationManager
      .requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 10, mLocationListener, Looper
            .myLooper());
    locationManager
      .requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 10, mLocationListener, Looper
            .myLooper());
</pre></div>
<p>如果只需要获取一次位置信息,获取后可以取消位置监听。</p>
<div class="jb51code"><pre class="brush:java;">    locationManager.removeUpdates(mLocationListener);
</pre></div>
<p><strong>3.获取最近一次位置信息</strong></p>
<p>有时候由于各种原因例如在室内、网络问题等,导致注册的位置监听无法及时返回位置信息,这个时候可以使用 <code>getLastKnownLocation</code> 方法返回一个从给定提供程序获得的最后一个已知位置数据。</p>
<div class="jb51code"><pre class="brush:java;">private Location getLastLocation() {
    Location location = null;

    LocationManager locationManager = (LocationManager) SDWanVPNApplication.getAppContext()
      .getSystemService(LOCATION_SERVICE);
    if (locationManager == null) {
      return null;
    }
    List&lt;String&gt; providers = locationManager.getProviders(true);
    for (String provider : providers) {
      Location l = locationManager.getLastKnownLocation(provider);
      if (l == null) {
      continue;
      }
      if (location == null || l.getAccuracy() &lt; location.getAccuracy()) {
      // Found best last known location: %s", l);
      location = l;
      }
    }
    return location;

}
</pre></div>
<p><strong>4.通过经纬度获取详细地址</strong></p>
<p><code>Geocoder</code> 相关API,支持通过经纬度获取详细位置信息</p>
<div class="jb51code"><pre class="brush:java;">public static void getAddress(double latitude, double longitude) {
    List&lt;Address&gt; addressList = null;
    Geocoder geocoder = new Geocoder(MyApplication.getAppContext());
    try {
      addressList = geocoder.getFromLocation(latitude, longitude, 1);
    } catch (IOException e) {
      e.printStackTrace();
    }
    if (addressList != null) {
      for (Address address : addressList) {
      Log.d(TAG, String.format("address: %s", address.toString()));
      }
    }
}
</pre></div>
<p>打印结果如下:</p>
<blockquote><p>address: Address,feature=null,admin=福建省,sub-admin=后溪镇,locality=厦门市,thoroughfare=诚毅北大街,postalCode=null,countryCode=CN,countryName=中国,hasLatitude=true,latitude=24.622825253598176,hasLongitude=true,longitude=118.05078728444207,phone=null,url=null,extras=null]</p></blockquote>
<p><strong>5.坐标系介绍</strong></p>
<p>获取经纬度后在地图上查询发现,位置存在一定偏移,这个是因为使用的坐标系不一致引起的。</p>
<p>我国出于安全的考虑,会将所有的电子地图经行加偏处理,由真实的地理坐标系又称地球坐标系(WGS84)转换为火星坐标系(GCJ02),但是使用 <code>location</code> 获取的经纬度又是WGS84坐标系的,所以再其他地图上显示会出现位置偏移现象。</p>
<p>目前坐标系主要有以下几种:</p>
<ul><li>WGS84坐标系:地球坐标系,国际通用坐标系</li><li>GCJ02坐标系:火星坐标系,WGS84坐标系加密后的坐标系,Google国内地图、高德、QQ地图使用</li><li>BD09坐标系:百度坐标系,GCJ02坐标系加密后的坐标系</li></ul>
<p>可以调用你所使用的地图的服务商提供的坐标系转换接口进行坐标转换。</p>
<p>到此这篇关于Android实现获取定位信息的工具类的文章就介绍到这了,更多相关Android获取定位信息内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>Android 高德地图POI定位地址搜索功能</li><li>Android通过GPS获取定位的流程步骤</li><li>Android 模拟地图定位功能的实现</li><li>Android 简单服务定位器模式实现</li><li>Android获取位置信息的方法</li><li>Android获取手机位置的实现代码</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Android实现获取定位信息的工具类