美文网首页Android开发Android开发经验谈
Android原生方式获取经纬度和城市信息

Android原生方式获取经纬度和城市信息

作者: 812cdf61e052 | 来源:发表于2020-07-29 11:16 被阅读0次

    Android核心知识点笔记github:https://github.com/AndroidCot/Android

    一、概述

    在项目中需要获取用户所在位置的经纬度和城市上送给风控系统。一般来说,定位有两种方式:

    1. 用第三方SDK定位,如百度地图、高德地图、谷歌地图;
    2. 用Android原生SDK中的api定位;

    本文讲述定位的第二种方式--用Android原生的SDK中的api定位,如果项目定位要求较高还是建议使用第三方地图库。

    二、Android原生SDK中的api定位

    Android原生方式获取经纬度两种定位方式:GPS定位和Wifi定位

    • GPS定位相比Wifi定位更精准且可在无网络情况下使用,但在室内基本暴毙无法使用。
    • WiFi定位没有室内外限制,也不需要开启GPS但需要联网。但测试发现WiFi定位时onLocationChanged函数(用于监听经纬度变化)触发间隔无法小于30s。

    示例代码如下:

    public class TestLocationActivity extends AppCompatActivity {
    
        public static final int LOCATION_CODE = 301;
        private LocationManager locationManager;
        private String locationProvider = null;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            getLocation();
        }
    
        private void getLocation(){
            //1.获取位置管理器
            locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    
            //2.获取位置提供器,GPS或是NetWork
            List<String> providers = locationManager.getProviders(true);
    
            if (providers.contains(LocationManager.GPS_PROVIDER)) {
                //如果是GPS
                locationProvider = LocationManager.GPS_PROVIDER;
                Log.v("TAG", "定位方式GPS");
            } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
                //如果是Network
                locationProvider = LocationManager.NETWORK_PROVIDER;
                Log.v("TAG", "定位方式Network");
            }else {
                Toast.makeText(this, "没有可用的位置提供器", Toast.LENGTH_SHORT).show();
                return;
            }
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                //获取权限(如果没有开启权限,会弹出对话框,询问是否开启权限)
                if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) 
                        != PackageManager.PERMISSION_GRANTED || 
                    ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) 
                        != PackageManager.PERMISSION_GRANTED) {
                    //请求权限
                    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
                            Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_CODE);
                } else {
                    //3.获取上次的位置,一般第一次运行,此值为null
                    Location location = locationManager.getLastKnownLocation(locationProvider);
                    if (location!=null){
                        Toast.makeText(this, location.getLongitude() + " " + 
                                             location.getLatitude() + "",Toast.LENGTH_SHORT).show();
                        Log.v("TAG", "获取上次的位置-经纬度:"+location.getLongitude()+"   "+location.getLatitude());
                        getAddress(location);
    
                    }else{
                        //监视地理位置变化,第二个和第三个参数分别为更新的最短时间minTime和最短距离minDistace
                        locationManager.requestLocationUpdates(locationProvider, 3000, 1,locationListener);
                    }
                }
            } else {
                Location location = locationManager.getLastKnownLocation(locationProvider);
                if (location!=null){
                    Toast.makeText(this, location.getLongitude() + " " + 
                                         location.getLatitude() + "", Toast.LENGTH_SHORT).show();
                    Log.v("TAG", "获取上次的位置-经纬度:"+location.getLongitude()+"   "+location.getLatitude());
                    getAddress(location);
    
                }else{
                    //监视地理位置变化,第二个和第三个参数分别为更新的最短时间minTime和最短距离minDistace
                    locationManager.requestLocationUpdates(locationProvider, 3000, 1,locationListener);
                }
            }
        }
    
        public LocationListener locationListener = new LocationListener() {
            // Provider的状态在可用、暂时不可用和无服务三个状态直接切换时触发此函数
            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
            }
            // Provider被enable时触发此函数,比如GPS被打开
            @Override
            public void onProviderEnabled(String provider) {
            }
            // Provider被disable时触发此函数,比如GPS被关闭
            @Override
            public void onProviderDisabled(String provider) {
            }
            //当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发
            @Override
            public void onLocationChanged(Location location) {
                if (location != null) {
                    //如果位置发生变化,重新显示地理位置经纬度
                    Toast.makeText(TestLocationActivity.this, location.getLongitude() + " " + 
                                                              location.getLatitude() + "", Toast.LENGTH_SHORT).show();
                    Log.v("TAG", "监视地理位置变化-经纬度:"+location.getLongitude()+"   "+location.getLatitude());
                }
            }
        };
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            switch (requestCode) {
                case LOCATION_CODE:
                    if(grantResults.length > 0 && grantResults[0] == getPackageManager().PERMISSION_GRANTED
                            && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                        Toast.makeText(this, "申请权限", Toast.LENGTH_LONG).show();
                        try {
                            List<String> providers = locationManager.getProviders(true);
                            if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
                                //如果是Network
                                locationProvider = LocationManager.NETWORK_PROVIDER;
    
                            }else if (providers.contains(LocationManager.GPS_PROVIDER)) {
                                //如果是GPS
                                locationProvider = LocationManager.GPS_PROVIDER;
                            }
                            Location location = locationManager.getLastKnownLocation(locationProvider);
                            if (location!=null){
                                Toast.makeText(this, location.getLongitude() + " " + 
                                                     location.getLatitude() + "", Toast.LENGTH_SHORT).show();
                                Log.v("TAG", "获取上次的位置-经纬度:"+location.getLongitude()+"   "+location.getLatitude());
                            }else{
                                // 监视地理位置变化,第二个和第三个参数分别为更新的最短时间minTime和最短距离minDistace
                                locationManager.requestLocationUpdates(locationProvider, 0, 0,locationListener);
                            }
    
                        }catch (SecurityException e){
                            e.printStackTrace();
                        }
                    } else {
                        Toast.makeText(this, "缺少权限", Toast.LENGTH_LONG).show();
                        finish();
                    }
                    break;
            }
        }
    
        //获取地址信息:城市、街道等信息
        private List<Address> getAddress(Location location) {
            List<Address> result = null;
            try {
                if (location != null) {
                    Geocoder gc = new Geocoder(this, Locale.getDefault());
                    result = gc.getFromLocation(location.getLatitude(),
                            location.getLongitude(), 1);
                    Toast.makeText(this, "获取地址信息:"+result.toString(), Toast.LENGTH_LONG).show();
                    Log.v("TAG", "获取地址信息:"+result.toString());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            locationManager.removeUpdates(locationListener);
        }
    
    }
    

    在AndroidManifest.xml加权限

    <!-- 粗略的位置权限 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission> 
    <!-- 精确的位置权限 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    复制代码
    

    三、总结

    首先将手机定位服务设置,调到下图所示:

    这可能会获取不到经纬度。为什么在网络和GPS都可用的情况下只执行GPS而不是网络?也许是从精确度考虑的,但是走GPS进入监听的listener后,不会执行onLocationChanged()方法,因为我是在室内,没有移动,所以如果你获取不到经纬度,就要将定位服务调到仅使用网络定位或者关闭手机GPS这样就可以获取到了。

    相关文章

      网友评论

        本文标题:Android原生方式获取经纬度和城市信息

        本文链接:https://www.haomeiwen.com/subject/gllhrktx.html