尝试封装高德地图定位的一些疑问

尝试封装高德地图定位的一些疑问

查看高德定位Demo,分析后主要有几步

配置参数->开始定位->关闭定位->onDestory()释放资源


设计思路:

  1. 低侵入性--其他module不会耦合到定位SDK的代码

  2. 傻瓜式使用--结合lifecycle监听页面自动释放资源,用户调用方法处理回调即可

相关代码:

internal class AppLocationHelper {

    private var locationClient: AMapLocationClient? = null
    private var locationOption: AMapLocationClientOption? = null
    private var appLocationListener: IAppLocationListener? = null

    /**
     * 开始定位
     */
    fun startLocation(activity: FragmentActivity, iAppLocationListener: IAppLocationListener?) {
        this.appLocationListener = iAppLocationListener
        activity.lifecycle.addObserver(AppLifecycleObserver())
        //初始化client
        locationClient = AMapLocationClient(activity.applicationContext)
        locationOption = getDefaultOption()
        locationClient?.apply {
            //设置定位参数
            setLocationOption(locationOption)
            // 设置定位监听
            setLocationListener(locationListener)
            // 启动定位
            startLocation()
        }
    }

    private fun destroyLocation() {
        if (null != locationClient) {
            /**
             * 如果AMapLocationClient是在当前Activity实例化的,
             * 在Activity的onDestroy中一定要执行AMapLocationClient的onDestroy
             *
             * 由于我们设计成一次性定位,因此停止定位同时释放资源
             */
            locationClient?.stopLocation()
            locationClient?.onDestroy()
            locationClient = null
            locationOption = null
        }
    }

    /**
     * 默认的定位参数
     *
     */
    private fun getDefaultOption(): AMapLocationClientOption {
       //....
        return mOption
    }

    private val locationListener = AMapLocationListener { location ->
        //a!=null和null!=a 效果一样,但后者可以避免一些赋值异常,equal类似,把常量放在前面
        if (null != appLocationListener && null != location) {
            appLocationListener?.onLocationChanged(toJsonObject(location))
        }
    }

    /*
       错误码errorCode说明
       具体看R.string.amapErrorCodeInfo
     */
    private fun toJsonObject(location: AMapLocation): JSONObject {
        val jsonObject = JSONObject()
        jsonObject.put("latitude", location.latitude)
        jsonObject.put("longitude", location.longitude)
        jsonObject.put("province", location.province)
        jsonObject.put("coordType", location.coordType)
        jsonObject.put("city", location.city)
        jsonObject.put("district", location.district)
        jsonObject.put("cityCode", location.cityCode)
        jsonObject.put("adCode", location.adCode)
        jsonObject.put("address", location.address)
        jsonObject.put("country", location.country)
        jsonObject.put("poiName", location.poiName)
        jsonObject.put("street", location.street)
        jsonObject.put("streetNum", location.streetNum)
        jsonObject.put("aoiName", location.aoiName)
        jsonObject.put("floor", location.floor)
        jsonObject.put("errorCode", location.errorCode)
        jsonObject.put("errorInfo", location.errorInfo)
        jsonObject.put("locationDetail", location.locationDetail)
        jsonObject.put("description", location.description)
        jsonObject.put("locationType", location.locationType)
        jsonObject.put("conScenario", location.conScenario)
        return jsonObject
    }

    /**
     * LifecycleObserver监听当前承载的Activity的生命周期
     */
    inner class AppLifecycleObserver : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        fun onDestroy() {
            destroyLocation()
        }
    }

}


疑问一:

var locationClient=AMapLocationClient(activity.applicationContext)持有content,如果 AppLocationHelper 定义成 object类, locationClient会警告内存泄漏,这个该怎么优化,没找到方案


疑问二:

startLocation(activity: FragmentActivity) 这样封装的传参,一般用哪个比较合适,Activity/FragmentActivity/ComponentActivity,这几个都能用,有点纠结





正在回答 回答被采纳积分+1

登陆购买课程后可参与讨论,去登陆

1回答
CrazyCodeBoy 2021-06-08 14:11:18
  1. 对于定位相关的功能逻辑通常会将AppLocationHelper职能的类设计成单例,为了防止AMapLocationClient中的context内存泄漏问题,建议获取应用的application的context;

  2. 对于开始定位这个功能主要关注点是:

    1. 定位成功;

    2. 定位失败

所以,建议startLocation方法的入参定义为一个包含定位成功和定位失败两个方法的接口,这样也能和activity解耦。

注意,这种情况下单例不要用object,因为此种形式的单例会被编译成:

public final class AppLocationHelper {
   private static AMapLocationClient locationClient;
   private static AMapLocationClientOption locationOption;
   public static final AppLocationHelper INSTANCE;

   private AppLocationHelper() {
   }

   static {
      AppLocationHelper var0 = new AppLocationHelper();
      INSTANCE = var0;
   }
}

locationClient被修饰成静态变量,AS的静态代码估计也是基于这个识别的,可以用课程中讲的静态内部类式的单例来实现。


  • 提问者 默小铭 #1
    1. 老师,我传activity的原因是因为要用LifecycleObserver监听activity的生命周期,然后直接在当前Helper类停止定位,然后释放资源

    2. 然后我现在 class AppLocationHelper 改成 object AppLocationHelper ,这种写法kotlin转jvava一看,其实就是实现了单例了,我的疑问是  private var locationClient: AMapLocationClient? = null 会有警告,报Do not place Android context classes in static fields (static reference to AMapLocationClient which has field a pointing to Context); this is a memory leak,想问下老师优化方案  0.0

    2021-06-08 14:55:15
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师