106.android简单的GPS实时定位

//定位权限、网络权限:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET" />

//GPS开关和app定位权限手动打开,这里未提供。以下定位代码:

//以下是定位工具类:

/**
 * 系统定位工具类
 * todo:注意 LocationManager.NETWORK_PROVIDER、 LocationManager.GPS_PROVIDER、 LocationManager.PASSIVE_PROVIDER
 * <p>
 * GPS_PROVIDER:这个就是手机里有GPS芯片,然后利用该芯片就能利用卫星获得自己的位置信息。可是在室内,GPS定位基本没用,非常难定位的到。
 * <p>
 * NETWORK_PROVIDER:这个就是利用网络定位,一般是利用手机基站和WIFI节点的地址来大致定位位置,
 * 这样的定位方式取决于server,即取决于将基站或WIF节点信息翻译成位置信息的server的能力。
 * 因为眼下大部分Android手机没有安装google官方的location manager库。
 * 大陆网络也不同意。即没有server来做这个事情,自然该方法基本上没法实现定位。
 * <p>
 * PASSIVE_PROVIDER:被动定位方式。
 * 这个意思也比較明显。就是用现成的,当其它应用使用定位更新了定位信息。
 * 系统会保存下来。该应用接收到消息后直接读取就能够了。
 * 比方假设系统中已经安装了百度地图,高德地图(室内能够实现精确定位)。
 * 你仅仅要使用它们定位过后。再使用这样的方法在你的程序肯定是能够拿到比較精确的定位信息。
 * <p>
 * 仅仅有NETWORK_PROVIDER这样的模式才是室内定位可靠的方式,
 * 因为大陆的特殊网络,且大部分厂商也不会用google的服务,这样的定位方式默认是没法用的。
 * 推荐使用其他三方定位sdk
 * <p>
 * (1)GPS_PROVIDER:通过 GPS 来获取地理位置的经纬度信息;优点:获取地理位置信息精确度高;缺点:只能在户外使用,获取经纬度信息耗时,耗电;
 * (2)NETWORK_PROVIDER:通过移动网络的基站或者 Wi-Fi 来获取地理位置;优点:只要有网络,就可以快速定位,室内室外都可;缺点:精确度不高;
 * (3)PASSIVE_PROVIDER:被动接收更新地理位置信息,而不用自己请求地理位置信息。
 * PASSIVE_PROVIDER 返回的位置是通过其他 providers 产生的,可以查询 getProvider() 方法决定位置更新的由来,需要 ACCESS_FINE_LOCATION 权限,但是如果未启用 GPS,则此 provider 可能只返回粗略位置匹配;
 * (4)FUSED_PROVIDER:这个本来已经被废弃了,但是目前在Android12(即android api 31)上又重新使用了起来,但是它依赖GMS,所以国内暂时无法使用。
 * 我们通常使用gps和network这两种方式。
 * <p>
 * 室内实测:GPS_PROVIDER无效、PASSIVE_PROVIDER无效、NETWORK_PROVIDER有效但不是特别准确
 *
 * @author CJF
 */
public class LocationManagerUtil {
    private volatile static LocationManagerUtil locationManagerUtil = null;
    private final String TAG = "LocationManagerUtil";
    private final Context context = RecordApp.context;
    private final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    private LocationManagerListener listener;
    private final Handler handler = new Handler(Looper.myLooper());

    /**
     * 超时时间10秒
     */
    private final long TIME_OUT = 10000;

    /**
     * 超时结束监听标记
     */
    private boolean endlistenerFlag = false;

    public static LocationManagerUtil getInstance() {
        if (null == locationManagerUtil) {
            synchronized (LocationManagerUtil.class) {
                if (null == locationManagerUtil) {
                    locationManagerUtil = new LocationManagerUtil();
                }
            }
        }
        return locationManagerUtil;
    }

    /**
     * 开始定位 单次定位
     *
     * @param listener
     */
    public void startSingleLocation(LocationManagerListener listener) {
        this.listener = listener;
        endlistenerFlag = false;

        if (null == locationManager) {
            XLog.d(TAG, "locationManager=null return");
            return;
        }

        //获取当前网络状态
        boolean networkState = CommonMethod.checkNetworkState();

        if (!networkState) {
            XLog.d(TAG, "无网络 return");
            return;
        }

扫描二维码关注公众号,回复: 15432318 查看本文章

        //检查权限
        boolean permission = checkPermission();
        if (!permission) {
            XLog.d(TAG, "定位权限未开启 return");
            return;
        }

        String provider = LocationManager.NETWORK_PROVIDER;
        XLog.d(TAG, "provider:" + provider);

        //判断provider是否可用
        boolean providerEnabled = locationManager.isProviderEnabled(provider);
        if (!providerEnabled) {
            XLog.d(TAG, provider + " 不可用 return");
            return;
        }

        //获取缓存中的位置信息getLastKnownLocation
        Location location = locationManager.getLastKnownLocation(provider);
        if (null != location) {
            String locationAddr = getLocationAddr(location.getLongitude(), location.getLatitude());
            XLog.d(TAG, "缓存中的位置信息location:" + location.toString());
            XLog.d(TAG, "缓存中的位置信息locationAddr:" + locationAddr);
            //清除定位信息
            location.reset();
        }

//        getWifi();
//
//        getTelephonyManager();

        //        Criteria crite = new Criteria();
//        crite.setAccuracy(Criteria.ACCURACY_FINE); //精度
//        crite.setPowerRequirement(Criteria.POWER_LOW); //功耗类型选择
//        String provider = locationManager.getBestProvider(crite, true);

//        String networkProvider = LocationManager.NETWORK_PROVIDER;
//        String gpsProvider = LocationManager.GPS_PROVIDER;
//        String passiveProvider = LocationManager.PASSIVE_PROVIDER;

        //添加地理围栏
//        locationManager.addProximityAlert(38.234, 114.234, 5, -1, PendingIntent.getBroadcast(this, 1, new Intent(), 3));
//        可以设置一个区域,当进入或离开这个区域的时候会收到通知,前两个参数指定一个点,第三个参数是半径,第四个参数是超时时间,设置为-1表示不存在超时,最后一个是广播接收器。
//        触发的Intent将使用键KEY_PROXIMITY_ENTERING,如果值为true,则设备进入邻近区域,如果是false,说明设备离开该区域。

        //获取一次定位结果requestSingleUpdate  单次定位
        locationManager.requestSingleUpdate(provider, locationListener, handler.getLooper());

        //超时结束定位
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                locationManager.removeUpdates(locationListener);
                handler.removeCallbacks(this);
                if (!endlistenerFlag) {
                    XLog.d(TAG, "定位超时");
                    onFailureListener();
                }
            }
        }, TIME_OUT);
    }

    /**
     * 开始定位 持续定位
     *
     * @param listener
     */
    public void startLocationUpdates(LocationManagerListener listener) {
        this.listener = listener;
        endlistenerFlag = false;

        if (null == locationManager) {
            XLog.d(TAG, "locationManager=null return");
            return;
        }

        //获取当前网络状态
        boolean networkState = CommonMethod.checkNetworkState();

        if (!networkState) {
            XLog.d(TAG, "无网络 return");
            return;
        }

        //检查权限
        boolean permission = checkPermission();
        if (!permission) {
            XLog.d(TAG, "定位权限未开启 return");
            return;
        }

        String provider = LocationManager.NETWORK_PROVIDER;
        XLog.d(TAG, "provider:" + provider);

        //判断provider是否可用
        boolean providerEnabled = locationManager.isProviderEnabled(provider);
        if (!providerEnabled) {
            XLog.d(TAG, provider + " 不可用 return");
            return;
        }

        //获取缓存中的位置信息getLastKnownLocation
        Location location = locationManager.getLastKnownLocation(provider);
        if (null != location) {
            String locationAddr = getLocationAddr(location.getLongitude(), location.getLatitude());
            XLog.d(TAG, "缓存中的位置信息location:" + location.toString());
            XLog.d(TAG, "缓存中的位置信息locationAddr:" + locationAddr);
            //清除定位信息
            location.reset();
        }

//        Criteria crite = new Criteria();
//        crite.setAccuracy(Criteria.ACCURACY_FINE); //精度
//        crite.setPowerRequirement(Criteria.POWER_LOW); //功耗类型选择
//        String provider = locationManager.getBestProvider(crite, true);

//        String networkProvider = LocationManager.NETWORK_PROVIDER;
//        String gpsProvider = LocationManager.GPS_PROVIDER;
//        String passiveProvider = LocationManager.PASSIVE_PROVIDER;

        //添加地理围栏
//        locationManager.addProximityAlert(38.234, 114.234, 5, -1, PendingIntent.getBroadcast(this, 1, new Intent(), 3));
//        可以设置一个区域,当进入或离开这个区域的时候会收到通知,前两个参数指定一个点,第三个参数是半径,第四个参数是超时时间,设置为-1表示不存在超时,最后一个是广播接收器。
//        触发的Intent将使用键KEY_PROXIMITY_ENTERING,如果值为true,则设备进入邻近区域,如果是false,说明设备离开该区域。

        //持续定位:
        //绑定监听,有4个参数
        //参数1,设备:有GPS_PROVIDER、NETWORK_PROVIDER、PASSIVE_PROVIDER  三种
        //参数2,位置信息更新周期,单位毫秒
        //参数3,位置变化最小距离:当位置距离变化超过此值时,将更新位置信息
        //参数4,监听
        //备注:参数2和3,如果参数3不为0,则以参数3为准;参数3为0,则通过时间来定时更新;两者为0,则随时刷新
        // 1分钟更新一次,或最小位移变化超过1米更新一次;
        locationManager.requestLocationUpdates(provider, 60 * 1000, 0, locationListener, handler.getLooper());

        //超时结束定位
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                locationManager.removeUpdates(locationListener);
                handler.removeCallbacks(this);
                if (!endlistenerFlag) {
                    XLog.d(TAG, "定位超时");
                    onFailureListener();
                }
            }
        }, TIME_OUT);
    }

    /**
     * 定位监听
     */
    private final LocationListener locationListener = new LocationListener() {
        /**
         * 位置信息变化时触发
         * 当位置发生改变后就会回调该方法,经纬度相关信息存在Location里面;
         */
        @Override
        public void onLocationChanged(Location location) {
            //赋值为true
            endlistenerFlag = true;
            if (null != locationManager) {
                //解除注册监听 结束定位
                locationManager.removeUpdates(this);
            }
            String time = DateTimeUtility.formatDateTime(location.getTime(), 0);
            final double longitude = location.getLongitude();
            final double latitude = location.getLatitude();
            double altitude = location.getAltitude();
            double longitudeGd = location.getLongitude() + 0.0052719116;//经度 系统定位相对于高德定位坐标相差0.0052719116
            double latitudeGd = location.getLatitude() + 0.0010604858;//纬度 系统定位相对于高德定位坐标相差0.0010604858

            //获取地理位置
            String locationAddr = getLocationAddr(longitude, latitude);
            //获取高德经纬度地址
            String locationAddrGd = getLocationAddr(longitudeGd, latitudeGd);

            XLog.d(TAG, "时间:" + time);
            XLog.d(TAG, "经度:" + longitude);
            XLog.d(TAG, "纬度:" + latitude);
            XLog.d(TAG, "海拔:" + altitude);
            XLog.d(TAG, "位置:" + locationAddr);
            XLog.d(TAG, "高德经度:" + longitudeGd);
            XLog.d(TAG, "高德纬度:" + latitudeGd);
            XLog.d(TAG, "高德位置:" + locationAddrGd);


            if (TextUtils.isEmpty(locationAddr)) {
                //失败回调
                onFailureListener();
            } else {
                //成功回调
                onSuccessListener(locationManager, location, longitudeGd, latitudeGd, locationAddr);
            }
        }

        /**
         * GPS状态变化时触发
         * 我们所采用的provider状态改变时会回调
         */
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            switch (status) {
                //GPS状态为可见时
                case LocationProvider.AVAILABLE:
                    Log.d(TAG, "当前GPS状态为可见状态 provider可用");
                    break;
                //GPS状态为服务区外时
                case LocationProvider.OUT_OF_SERVICE:
                    Log.d(TAG, "当前GPS状态为服务区外状态 无服务");
                    break;
                //GPS状态为暂停服务时
                case LocationProvider.TEMPORARILY_UNAVAILABLE:
                    Log.d(TAG, "当前GPS状态为暂停服务状态 provider不可用");
                    break;
                default:
                    break;
            }
        }

        /**
         * GPS开启时触发
         * 当provider可用时被触发,比如定位模式切换到了使用精确位置时GPSProvider就会回调该方法;
         */
        @Override
        public void onProviderEnabled(String provider) {

        }

        /**
         * GPS禁用时触发
         * 当provider不可用时被触发,比如定位模式切换到了使用使用网络定位时GPSProvider就会回调该方法;
         */
        @Override
        public void onProviderDisabled(String proider) {

        }
    };

    /**
     * 检查权限
     *
     * @return
     */
    private boolean checkPermission() {
        if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, android.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.
            CommonMethod.showToast("请开启定位权限");
            return false;
        }
        return true;
    }

    /**
     * wifi定位 不准确
     */
    private void getWifi() {
        WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        if (null == wifiManager) {
            XLog.d(TAG, "null == wifiManager return");
            return;
        }
        if (!wifiManager.isWifiEnabled()) {
            XLog.d(TAG, "wifi未启用 return");
            return;
        }
        WifiInfo connectionInfo = wifiManager.getConnectionInfo();
        String ssid = connectionInfo.getSSID();
        final String bssid = connectionInfo.getBSSID();
        int ipAddress = connectionInfo.getIpAddress();
        @SuppressLint("HardwareIds") String macAddress = connectionInfo.getMacAddress();
        String string = connectionInfo.toString();
        XLog.d(TAG, "wifi名称:" + ssid);
        XLog.d(TAG, "wifi的mac:" + bssid);
        XLog.d(TAG, "ipAddress:" + ipAddress);
        XLog.d(TAG, "macAddress:" + macAddress);
        XLog.d(TAG, "string:" + string);

        ThreadPoolExecutorUtil.getInstance().startThread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL("http://api.cellocation.com:83/wifi/?mac=" + bssid + "&output=json");
                    XLog.d(TAG, "url:" + url.toString());
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    //超时时间
                    connection.setConnectTimeout(3000);
                    //表示设置本次http请求使用GET方式
                    connection.setRequestMethod("GET");
                    //返回至为响应编号,如:HTTP_OK表示连接成功。
                    int responsecode = connection.getResponseCode();
                    if (responsecode == HttpURLConnection.HTTP_OK) {
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                        String result = bufferedReader.readLine();
                        XLog.d(TAG, "result:" + result);
                    } else {
                        XLog.d(TAG, "result responsecode:" + responsecode);
                    }
                    connection.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 手机基站信息定位 不准确
     */
    private void getTelephonyManager() {
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, 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;
        }
        TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        if (null == manager) {
            return;
        }
        String networkOperator = manager.getNetworkOperator();
        if (TextUtils.isEmpty(networkOperator)) {
            return;
        }
        GsmCellLocation location = (GsmCellLocation) manager.getCellLocation();
        final int mcc = Integer.parseInt(networkOperator.substring(0, 3));
        final int mnc = Integer.parseInt(networkOperator.substring(3));
        final int lac = location.getLac();
        final int cid = location.getCid();
        XLog.d(TAG, "mcc:" + mcc);
        XLog.d(TAG, "mnc:" + mnc);
        XLog.d(TAG, "lac:" + lac);
        XLog.d(TAG, "cid:" + cid);

        ThreadPoolExecutorUtil.getInstance().startThread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL("http://api.cellocation.com:83/cell/?mcc=" + mcc + "&mnc=" + mnc + "&lac=" + lac + "&ci=" + cid + "&output=json");
                    XLog.d(TAG, "url:" + url.toString());
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    //超时时间
                    connection.setConnectTimeout(3000);
                    //表示设置本次http请求使用GET方式
                    connection.setRequestMethod("GET");
                    //返回至为响应编号,如:HTTP_OK表示连接成功。
                    int responsecode = connection.getResponseCode();
                    if (responsecode == HttpURLConnection.HTTP_OK) {
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                        String result = bufferedReader.readLine();
                        XLog.d(TAG, "result:" + result);
                    } else {
                        XLog.d(TAG, "result responsecode:" + responsecode);
                    }
                    connection.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 获取网络位置
     *
     * @param longitude
     * @param latitude
     */
    private void getNetworkAddress(final double longitude, final double latitude) {
        ThreadPoolExecutorUtil.getInstance().startThread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL("http://api.cellocation.com:83/regeo/?lat=" + latitude + "&lon=" + longitude + "&output=json");
                    XLog.d(TAG, "url:" + url.toString());
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    //超时时间
                    connection.setConnectTimeout(3000);
                    //表示设置本次http请求使用GET方式
                    connection.setRequestMethod("GET");
                    //返回至为响应编号,如:HTTP_OK表示连接成功。
                    int responsecode = connection.getResponseCode();
                    if (responsecode == HttpURLConnection.HTTP_OK) {
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                        String result = bufferedReader.readLine();
                        XLog.d(TAG, "result:" + result);
                    } else {
                        XLog.d(TAG, "result responsecode:" + responsecode);
                    }
                    connection.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 获取地理位置
     *
     * @param longitude
     * @param latitude
     * @return
     */
    private String getLocationAddr(double longitude, double latitude) {
        Geocoder geocoder = new Geocoder(context, Locale.getDefault());
        boolean flag = Geocoder.isPresent();
        if (!flag) {
            XLog.d(TAG, "地理编码不可使用");
            return "";
        }

//        locality(地址位置) 属性
//        并且有featureName(地址要素)
//        比如国家(countryName)
//        邮编(postalCode)
//        国家编码(countryCode)
//        省份(adminArea)
//        二级省份(subAdminArea)
//        二级城市(subLocality)
//        道路(thoroughfare) 等;

        //  getFromLocationName():返回描述地理位置信息的集合,maxResults是返回地址的数目,建议使用1-5;
//        List<Address> addresses = geocoder.getFromLocationName("西二旗", 1);
//        if (addresses.size() > 0) {
//            //返回当前位置,精度可调
//            Address address = addresses.get(0);
//            if (address != null) {
//                Log.e("gzq", "sAddress:" + address.getLatitude());
//                Log.e("gzq", "sAddress:" + address.getLongitude());
//            }
//        }

        try {
            //根据经纬度返回对应的地理位置信息,参数maxResults表示返回地址的数目,建议使用1-5;
            List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
            if (addresses.size() == 0) {
                XLog.d(TAG, "addresses.size() == 0 return");
                return "";
            }
            Address address = addresses.get(0);
            if (null == address) {
                XLog.d(TAG, "null == address return");
                return "";
            }

            //获取最大地址行索引
            int maxAddressLineIndex = address.getMaxAddressLineIndex();
            //循环打印周围位置地址
            for (int i = 0; i < maxAddressLineIndex; i++) {
                String addressStr = address.getAddressLine(i);
                XLog.d(TAG, i + " addressStr:" + addressStr);
            }

            StringBuilder addressBuilder = new StringBuilder();
            String addressLine = address.getAddressLine(0);
            String addressLine1 = address.getAddressLine(1);
            if (null != addressLine) {
                addressBuilder.append(addressLine);
            }
            if (null != addressLine1) {
                addressBuilder.append("靠近").append(addressLine1);
            }
            XLog.d(TAG, "addressBuilder:" + addressBuilder);
            return addressBuilder.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    public interface LocationManagerListener {
        /**
         * 定位成功数据回调
         */
        void onSuccessLocationListener(LocationManager manager, Location location, double longitude, double latitude, String locationAddr);

        /**
         * 定位失败回调
         */
        void onFailureLocationListener();
    }

    private void onSuccessListener(LocationManager manager, Location location, double longitude, double latitude, String locationAddr) {
        if (null != listener) {
            listener.onSuccessLocationListener(manager, location, longitude, latitude, locationAddr);
        }
    }

    private void onFailureListener() {
        if (null != listener) {
            listener.onFailureLocationListener();
        }
    }

}

//调用工具类:

//调用代码
LocationManagerUtil.getInstance().startSingleLocation(new LocationManagerUtil.LocationManagerListener() {
    @Override
    public void onSuccessLocationListener(LocationManager manager, Location location, double longitude, double latitude, String locationAddr) {
        XLog.d(TAG, "定位成功");
        //本次定位时间
        long time = DateTimeUtil.getInstance().getNowLongTime();
        XLog.d(TAG, "本次定位地址address:" + locationAddr);
        XLog.d(TAG, "本次定位经度longitude:" + longitude);
        XLog.d(TAG, "本次定位纬度latitude:" + latitude);
        XLog.d(TAG, "本次定位时间time:" + time + "-" + DateTimeUtil.getInstance().formatDateTime(time, 0));
        XLog.d(TAG, "本次location.getTime()定位时间:" + location.getTime());

      
    }

    @Override
    public void onFailureLocationListener() {
        XLog.d(TAG, "定位失败");
    }
});

//---------------------------------------------------------------------------------------完---------------------------------------------------------------------------------

猜你喜欢

转载自blog.csdn.net/weixin_42061754/article/details/105224779