Android百度地图定位多处回调调用问题

Android百度地图定位多处回调调用问题

  • 多处回调调用问题
  • 改进

多处回调调用问题

为了方便使用,自己封装了一个百度地图定位工具。工具类没有使用单例模式,回调又用了一层handler来处理。每个activity都存在一个LocateUtil实例,本来想的是每个activity里定位工具都是独立的。但是实际运行时发现只要一处调用startLoaction,每个activity中的handler都会被调用。代码大概是这样的:

public class LocateUtil {
    private LocationClient mLocationClient;
    private BDLocationListener myListener;
    private Handler mHandler;

    public LocateUtil(Context context, Handler handler) {
        mHandler = handler;
        myListener = new MyLocationListener();
        mLocationClient = new LocationClient(context.getApplicationContext());
    }

    public void initLocation(int span) {
        initOption(span);
        mLocationClient.registerLocationListener(myListener);
    }

    public class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            Message msg = new Message();
           	msg.what = xxx;
           	//封装自己要用的数据 locationModel
           	msg.obj = locationModel;
            mHandler.sendMessage(msg);
        }
    }

    public void startLocation() {
        if (mLocationClient == null) {
            return;
        }
        if (mLocationClient.isStarted()) {
            mLocationClient.requestLocation();
        } else {
            mLocationClient.start();
        }
    }

    public void closeLocation() {
        if (mLocationClient != null) {
            mLocationClient.stop();
            mLocationClient.unRegisterLocationListener(myListener);
            mLocationClient = null;
        }
    }

    void initOption(int span) {
        LocationClientOption option = new LocationClientOption();
        //可选,默认gcj02,设置返回的定位结果坐标系
        option.setCoorType("bd09ll");
        //可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
        option.setScanSpan(span);
        //可选,设置是否需要地址信息,默认不需要
        option.setIsNeedAddress(true);
        //可选,默认false,设置是否使用gps
        option.setOpenGps(true);
        //可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
        option.setIsNeedLocationDescribe(true);
        //可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
        option.setIsNeedLocationPoiList(true);
        //可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
        option.setIgnoreKillProcess(false);
        //可选,默认false,设置是否收集CRASH信息,默认收集
        option.SetIgnoreCacheException(false);
        mLocationClient.setLocOption(option);
    }
}

查看了一下源码发现注册的回调是用一个list来存的(这源码看吐了,名字都是一些没有意义的字符,我改了改名字,稍微好看一点)

    private ArrayList<BDLocationListener> listenerList = null;
    private ArrayList<BDAbstractLocationListener> k = null;
    ...
    private void e(Message msg) {
        if (msg != null && msg.obj != null) {
            BDLocationListener listener = (BDLocationListener)msg.obj;
            if (this.listenerList == null) {
                this.listenerList = new ArrayList();
            }

            if (!this.listenerList.contains(listener)) {
                this.listenerList.add(listener);
            }
        }
    }

启动最后调用这个函数应该是启动了一个service,然后把LocationClient通过Notification(这个应该百度自己封装了一个,找不到源码)和Intent传递过去,

/**
    private void a(int var1, Notification var2) {
        try {
            Intent var3 = new Intent(this.f, f.class);
            var3.putExtra("notification", var2);
            var3.putExtra("id", var1);
            var3.putExtra("command", 1);
            if (VERSION.SDK_INT >= 26) {
                this.f.startForegroundService(var3);
            } else {
                this.f.startService(var3);
            }

            this.H = true;
        } catch (Exception var4) {
            ;
        }

    }
*/
LocationClient.a(this.a, 
new com.baidu.location.a.bdNotification(LocationClient.i(this.a), LocationClient.j(this.a), this.a));

后面的源码实在看不懂了,我猜测LoactionClient用list来存回调函数在service中应该也会有个回调list,当得到定位结果的时候会遍历list的回调,所以会发生一处调用start多出调用回调的现象。

改进

后来我把注册回调放在的startLocation里,注销放在回调里,调用startLocation时才把回调注册到service里,用完直接注销,这样一个地方用其他地方就不会调回调了(没考虑线程同步,我做的项目里没有多处同时调用定位的地方)

    public void startLocation() {
        if (mLocationClient == null) {
            return;
        }

        mLocationClient.registerLocationListener(myListener);
        if (mLocationClient.isStarted()) {
            mLocationClient.requestLocation();
        } else {
            mLocationClient.start();
        }
    }
    
    public class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            Message msg = new Message();
            ...
            mHandler.sendMessage(msg);
            if(span == 0){
                mLocationClient.unRegisterLocationListener(myListener);
            }
        }
    }

其实应该不需要用handler,直接在页面写自己的BDLocationListener回调应该更直观。

你可能感兴趣的:(Android遇到的问题)