美文网首页1-Android开发知识
Android定位辅助工具类-------快速实现第三方定位SD

Android定位辅助工具类-------快速实现第三方定位SD

作者: 想飞的小小李 | 来源:发表于2018-03-03 15:44 被阅读734次

    在开发中,会遇到一些定位的需求,我们可以使用系统提供的API来实现定位功能,但是大部分时候我们都会选择使用第三方定位SDK来实现定位功能。比如目前国内常用的定位SDK有百度地图、高德地图、腾讯地图等。

    这些定位SDK都有详细的接入文档,使用也很方便,但是我自己在使用时还是会有一些问题:

    1.动态权限的获取。

    2.对SDK的替换,比如在使用百度的SDK时出现了一些问题,需要替换到高德SDK,不可能去一个一个的替换含有百度定位的界面。

    为了让自己使用这些SDK更舒心,我自己写了一个定位的辅助工具类,既然可以更快速的对第三方SDK进行集成,也解决的上面的问题。

    首先,抽取一个定位回调监听接口,包含了定位成功、定位失败、没有权限的回调方法。在定位成功时locationSuccessful()方法会回调,并把 一些定位相关信息封装成 LocationModel 通过传参传递出来。

    public interface LocationCallBackListener {
    
        void locationSuccessful(LocationModel locationModel);//定位成功
    
        void locationFailure(String msg);//定位失败
    
        void noPermissions();//没有定位权限
    }
    
    

    然后再抽取一个定位实现的接口,具体的定位方法需要实现这个接口。

    public interface LocationInterface {
    
        void init(LocationCallBackListener listener); //定位的初始化
    
        void startLocation();  //开始定位
    
        void stopLocation(); //停止定位
    
        void destroyLocation();//销毁定位或一些资源释放
    
    }
    

    第三,新建一个类叫LocationHelper,这里面实现了对于动态权限的统一处理和对LocationInterface接口实现类的调用。
    其中 PermissionHelper 权限处理工具类参考自# android M权限适配,简单工具类

    /**
     * 定位辅助类 判断是否有定位权限
    
     * <p>
     * 使用注意 必须要调用onRequestPermissionsResult用于获取权限回调
     * <p>
     * 必须要在页面关闭时调用destroyLocation方法
     * <p>
     * Created by sx on 2017/8/7.
     */
    
    public class LocationHelper {
    
        private LocationInterface mLocationInterface;//定位实现接口
    
        private PermissionHelper mPreHelper;//权限请求
    
    
        private LocationCallBackListener mLocationCallBackListener;//定位回调
    
        //需要进行定位功能的权限
        private List<String> needLocationPermissions;
    
        public LocationHelper(@NonNull Object obj, @NonNull LocationInterface locationInterface, @NonNull LocationCallBackListener locationCallBackListener) {
            this.mLocationInterface = locationInterface;
            this.mLocationInterface.init(locationCallBackListener);
            this.mLocationCallBackListener = locationCallBackListener;
            needLocationPermissions = new ArrayList<>();
            mPreHelper = new PermissionHelper(obj);
        }
    
    
        /**
         * 添加还需要申请的权限
         *
         * @param permissions
         */
        public void addPermissions(String permissions) {
            needLocationPermissions.add(permissions);
        }
    
        /**
         * 需要的定位权限
         */
        private void setLocationPermissions() {
            needLocationPermissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
            needLocationPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
            needLocationPermissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
    
        /**
         * 启动定位
         */
        public void startLocation() {
            if (needRequestPermiss()) {
                setLocationPermissions();
                requestPermissions();
                return;
            }
            mLocationInterface.startLocation();
        }
    
        /**
         * 请求定位权限
         */
        private void requestPermissions() {
            mPreHelper.requestPermissions(new PermissionHelper.PermissionListener() {
                @Override
                public void doAfterGrand(String... permission) {
                    mLocationInterface.startLocation();
                }
    
                @Override
                public void doAfterDenied(String... permission) {
                    mLocationCallBackListener.noPermissions();
                }
            }, getPermissions());
        }
    
        private String[] getPermissions() {
            final int size = needLocationPermissions.size();
            String[] arr = needLocationPermissions.toArray(new String[size] );
            return arr;
        }
    
        /**
         * 是否需要申请权限
         *
         * @return
         */
        private boolean needRequestPermiss() {
            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
        }
    
        /**
         * 关闭定位
         */
        public void stopLocation() {
            mLocationInterface.stopLocation();
        }
    
        /**
         * 关闭一些内容
         */
        public void destroyLocation() {
            mLocationInterface.destroyLocation();
        }
    
        /**
         * 获取权限回调
         *
         * @param requestCode
         * @param permissions
         * @param grantResults
         */
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            if (mPreHelper == null) return;
            mPreHelper.handleRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    
    
    }
    

    到这里我们的定位辅助工具类已经写好了,让我们来看看怎么使用。这里以高德SDK为例。

    新建一个类叫GaoDeLocation并实现LocationInterface接口,其中主要实现了包括高德定位SDK的初始化、启动定位、结束等一些方法以及定位成功或失败的判断。

    **
     * 高德定位
     * 
     */
    public class GaoDeLocation implements LocationInterface {
    
        //定位功能
        protected AMapLocationClient locationClient = null;
    
        @Override
        public void init(final LocationCallBackListener listener) {
            //初始化client
            locationClient = new AMapLocationClient(MyApplication.getInstance());
            //设置定位参数
            locationClient.setLocationOption(getDefaultOption());
            // 设置定位监听
            locationClient.setLocationListener(new AMapLocationListener() {
                @Override
                public void onLocationChanged(AMapLocation aMapLocation) {
                    if (null != aMapLocation && aMapLocation.getErrorCode() == 0) {  //定位成功
                        listener.locationSuccessful(transitionModel(aMapLocation));
                    } else {
                        if (aMapLocation != null) {
                            listener.locationFailure(aMapLocation.getErrorInfo());
                            return;
                        }
                        listener.locationFailure("定位失败");
                    }
                    //停止定位
                    stopLocation();
                }
            });
        }
    
        @Override
        public void startLocation() {
            locationClient.startLocation();
        }
    
        @Override
        public void stopLocation() {
            locationClient.stopLocation();
        }
    
        @Override
        public void destroyLocation() {
            if (null != locationClient) {
                locationClient.onDestroy();
                locationClient = null;
            }
        }
    
        /**
         * 默认定位参数
         *
         * @return
         */
        private AMapLocationClientOption getDefaultOption() {
            AMapLocationClientOption mOption = new AMapLocationClientOption();
            mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式
            mOption.setGpsFirst(false);//可选,设置是否gps优先,只在高精度模式下有效。默认关闭
            mOption.setHttpTimeOut(30000);//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
            mOption.setInterval(2000);//可选,设置定位间隔。默认为2秒
            mOption.setNeedAddress(true);//可选,设置是否返回逆地理地址信息。默认是ture
            mOption.setOnceLocation(true);//可选,设置是否单次定位。默认是false
            mOption.setOnceLocationLatest(false);//可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用
            mOption.setLocationCacheEnable(false);  // 设置是否开启缓存
            AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);//可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
            return mOption;
        }
    
        /**
         * 把高德定位model转换为 自用model
         *
         * @return
         */
        private LocationModel transitionModel(AMapLocation aMapLocation) {
            LocationModel locationModel = new LocationModel();
            locationModel.setCity(aMapLocation.getCity());
            locationModel.setProvince(aMapLocation.getProvince());
            locationModel.setDistrict(aMapLocation.getDistrict());
            locationModel.setLatitude(aMapLocation.getLatitude() + "");
            locationModel.setLongitude(aMapLocation.getLongitude() + "");
            return locationModel;
        }
    
    }
    

    这里说明一下transitionModel() 方法,这是为了把高德SDK的定位model转为自己的model,因为不同SDK的定位model是不同,这里做一下转换,就是为了解决快速替换的问题。

    **用于定位
     * Created by cdkj on 2017/11/7.
     */
    
    public class LocationModel implements Parcelable {
    
        private String city;
    
        private String province;
    
        private String district;
    
        private String latitude;
    
        private String longitude;
    
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        public String getProvince() {
            return province;
        }
    
        public void setProvince(String province) {
            this.province = province;
        }
    
        public String getDistrict() {
            return district;
        }
    
        public void setDistrict(String district) {
            this.district = district;
        }
    
        public String getLatitude() {
            return latitude;
        }
    
        public void setLatitude(String latitude) {
            this.latitude = latitude;
        }
    
        public String getLongitude() {
            return longitude;
        }
    
        public void setLongitude(String longitude) {
            this.longitude = longitude;
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(this.city);
            dest.writeString(this.province);
            dest.writeString(this.district);
            dest.writeString(this.latitude);
            dest.writeString(this.longitude);
        }
    
        public LocationModel() {
        }
    
        protected LocationModel(Parcel in) {
            this.city = in.readString();
            this.province = in.readString();
            this.district = in.readString();
            this.latitude = in.readString();
            this.longitude = in.readString();
        }
    
        public static final Creator<LocationModel> CREATOR = new Creator<LocationModel>() {
            @Override
            public LocationModel createFromParcel(Parcel source) {
                return new LocationModel(source);
            }
    
            @Override
            public LocationModel[] newArray(int size) {
                return new LocationModel[size];
            }
        };
    }
    

    GaoDeLocation类实现之后就可以使用LocationHelper类了。

    先 new 一个 LocationHelper对象,第二个参数传入刚才的GaoDeLocation类。在需要开始定位的地方调用 mLocationHelperr.startLocation() 方法就可以进行定位了。

       LocationHelper  mLocationHelperr = new LocationHelper(MainActivity.this, new GaoDeLocation(), new LocationCallBackListener() {
                @Override
                public void locationSuccessful(LocationModel locationModel) {
                    mainBinding.tvLocationInfo.setText("高德定位结果" + locationModel.getCity());
                }
    
                @Override
                public void locationFailure(String msg) {
                    mainBinding.tvLocationInfo.setText("高德定位结果" + msg);
                }
    
                @Override
                public void noPermissions() {
                    mainBinding.tvLocationInfo.setText("高德定位结果没有定位权限");
                }
            });
    
        mLocationHelperr.startLocation();
    
    

    以上就实现了高德定位的过程,并且连权限管理也一并处理了,当然如果想把高德SDK替换成百度SDK也是非常简单的。我们可以把 GaoDeLocation 类 替换成 BaiDuLocation 类,这样就完成了替换。

    public class BaiDuLocation implements LocationInterface {
        public LocationClient mLocationClient = null;
    
        @Override
        public void init(final LocationCallBackListener listener) {
            mLocationClient = new LocationClient(MyApplication.getInstance());
            mLocationClient.setLocOption(getLocationClientOption());
            //mLocationClient为第二步初始化过的LocationClient对象
            //需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
            //更多LocationClientOption的配置,请参照类参考中LocationClientOption类的详细说明
            //声明LocationClient类
            mLocationClient.registerLocationListener(new BDAbstractLocationListener() {
                @Override
                public void onReceiveLocation(BDLocation location) {
    
                    if (location == null) {
                        return;
                    }
                    int errorCode = location.getLocType();
                    //获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
                    Log.i("location", errorCode + "");
                    if (errorCode == 61 || errorCode == 161) {
                        listener.locationSuccessful(transitionModel(location));
                    } else {
                        listener.locationFailure("定位失败");
                    }
                    stopLocation();
                }
            });
        }
    
        @NonNull
        private LocationClientOption getLocationClientOption() {
            LocationClientOption option = new LocationClientOption();
    
            option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
    //可选,设置定位模式,默认高精度
    //LocationMode.Hight_Accuracy:高精度;
    //LocationMode. Battery_Saving:低功耗;
    //LocationMode. Device_Sensors:仅使用设备;
    
            option.setCoorType("bd09ll");
    //可选,设置返回经纬度坐标类型,默认gcj02
    //gcj02:国测局坐标;
    //bd09ll:百度经纬度坐标;
    //bd09:百度墨卡托坐标;
    //海外地区定位,无需设置坐标类型,统一返回wgs84类型坐标
    
            option.setScanSpan(5000);
    //可选,设置发起定位请求的间隔,int类型,单位ms
    //如果设置为0,则代表单次定位,即仅定位一次,默认为0
    //如果设置非0,需设置1000ms以上才有效
    
            option.setOpenGps(true);
    //可选,设置是否使用gps,默认false
    //使用高精度和仅用设备两种定位模式的,参数必须设置为true
    
            option.setLocationNotify(true);
    //可选,设置是否当GPS有效时按照1S/1次频率输出GPS结果,默认false
    
            option.setIgnoreKillProcess(false);
    //可选,定位SDK内部是一个service,并放到了独立进程。
    //设置是否在stop的时候杀死这个进程,默认(建议)不杀死,即setIgnoreKillProcess(true)
            option.setWifiCacheTimeOut(5 * 60 * 1000);
    //可选,7.2版本新增能力
    //如果设置了该接口,首次启动定位时,会先判断当前WiFi是否超出有效期,若超出有效期,会先重新扫描WiFi,然后定位
    
            option.setEnableSimulateGps(false);
    
            option.setIsNeedAddress(true);
    
    //可选,设置是否需要过滤GPS仿真结果,默认需要,即参数为false
            return option;
        }
    
        @Override
        public void startLocation() {
            mLocationClient.start();
        }
    
        @Override
        public void stopLocation() {
            mLocationClient.stop();
        }
    
        @Override
        public void destroyLocation() {
            mLocationClient.stop();
            mLocationClient = null;
        }
    
        /**
         * 把百度定位model转换为 自用model
         *
         * @return
         */
        private LocationModel transitionModel(BDLocation bdLocation) {
            LocationModel locationModel = new LocationModel();
            locationModel.setCity(bdLocation.getCity());
            locationModel.setProvince(bdLocation.getProvince());
            locationModel.setDistrict(bdLocation.getDistrict());
            locationModel.setLatitude(bdLocation.getLatitude() + "");
            locationModel.setLongitude(bdLocation.getLongitude() + "");
            return locationModel;
        }
    }
    

    当然,在使用时还有两点需要注意:

    1:权限的处理回调,我们需要在页面的 onRequestPermissionsResult 方法中调用mLocationHelper的onRequestPermissionsResult() 方法,这样就实现了权限的处理。

        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            if (mLocationHelper != null) {
                mLocationHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    

    2:对资源的释放,在页面结束或销毁时调用mLocationHelper.destroyLocation()方法实现一些资源的释放。

        @Override
        protected void onDestroy() {
            super.onDestroy();
             if (mLocationHelper != null) {
                 mGdLocationHelper.destroyLocation();
            }
        }
    

    以上就是定位辅助类的实现及使用。

    相关文章

      网友评论

        本文标题:Android定位辅助工具类-------快速实现第三方定位SD

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