当百度定位遇上 RxJava

  • 2016-10-16
  • 6,997
  • 6

在项目中引入RxJava之后,得益于RxJava的各种优势,比如线程切换,避免死亡式回调,方便的数据流处理等等,便希望将所有用到回调的地方都用RxJava重写一遍。一大批使用RxJava的开源项目如雨后春笋般应运而生,RxBinding,RxBus,RxLifecycle,RxActivityResult,RxCache…

原项目中使用百度定位作为应用的定位服务,定位成功后通过回调的形式返回结果:

LocationClient mLocationClient = new LocationClient(getApplicationContext()); 
mLocationClient.registerLocationListener( new BDLocationListener() {
     @Override
        public void onReceiveLocation(BDLocation location) {
               //略
        }
});

我就想着能不能用RxJava包装一下,美其名曰RxLocation,说干就干:

使用单例模式简单的封装一下百度提供的LocationClient:

public class LocationClient {

    private com.baidu.location.LocationClient realClient;

    private static volatile LocationClient proxyClient;

    private LocationClient(Context context) {
        realClient = new com.baidu.location.LocationClient(context);
        LocationClientOption option = new LocationClientOption();
        //设置百度定位参数
        realClient.setLocOption(option);
    }

    public static LocationClient get(Context context) {
        if (proxyClient == null) {
            synchronized (LocationClient.class) {
                if (proxyClient == null) {
                    proxyClient = new LocationClient(context.getApplicationContext());
                }
            }
        }
        return proxyClient;
    }

    public void locate(final BDLocationListener bdLocationListener) {
        final BDLocationListener realListener = new BDLocationListener() {
            @Override
            public void onReceiveLocation(BDLocation bdLocation) {
                bdLocationListener.onReceiveLocation(bdLocation);
                //防止内存溢出
                realClient.unRegisterLocationListener(this);
                stop();
            }
        };
        realClient.registerLocationListener(realListener);
        if (!realClient.isStarted()) {
            realClient.start();
        }
    }

    public BDLocation getLateKnownLocation() {
        return realClient.getLastKnownLocation();
    }

    public void stop() {
        realClient.stop();
    }

}

用RxJava做回调的转发,RxLocation:

public class RxLocation {

    private static RxLocation instance = new RxLocation();

    private RxLocation () {}

    public static RxLocation get() {
        return instance;
    }

    public Observable<BDLocation> locate(Context context) {
        return Observable.create(new LocationOnSubscribe(context));
    }

    public Observable<BDLocation> locateLastKnown(Context context) {
        return Observable.create(new LocationLateKnownOnSubscribe(context));
    }

}

其中用到的两个OnSubsribe,一个是立即定位,一个是获取最近的一次定位,如果过去不到最近的定位再开始定位:

立即定位:

public class LocationOnSubscribe implements Observable.OnSubscribe<BDLocation> {

    private final Context context;

    public LocationOnSubscribe(Context context) {
        this.context = context;
    }

    @Override
    public void call(final Subscriber<? super BDLocation> subscriber) {
        BDLocationListener bdLocationListener = new BDLocationListener() {
            @Override
            public void onReceiveLocation(BDLocation bdLocation) {
                subscriber.onNext(bdLocation);
                subscriber.onCompleted();
            }
        };
        LocationClient.get(context).locate(bdLocationListener);
    }
}

获取最近一次定位信息:

public class LocationLateKnownOnSubscribe implements Observable.OnSubscribe<BDLocation> {

    private final Context context;

    public LocationLateKnownOnSubscribe(Context context) {
        this.context = context;
    }

    @Override
    public void call(final Subscriber<? super BDLocation> subscriber) {
        BDLocation lateKnownLocation = LocationClient.get(context).getLateKnownLocation();
        if (LocationUtil.isLocationResultEffective(lateKnownLocation)) {
            subscriber.onNext(lateKnownLocation);
            subscriber.onCompleted();
        } else {
            BDLocationListener bdLocationListener = new BDLocationListener() {
                @Override
                public void onReceiveLocation(BDLocation bdLocation) {
                    subscriber.onNext(bdLocation);
                    subscriber.onCompleted();
                }
            };
            LocationClient.get(context).locate(bdLocationListener);
        }
    }
}

为了使用更加方便,再封装一下Subscriber :

public abstract class LocationSubscriber extends Subscriber<BDLocation> {

    @Override
    public void onCompleted() {

    }

    @Override
    public void onError(Throwable throwable) {
        onLocatedFail(null);
    }

    @Override
    public void onNext(BDLocation bdLocation) {
        if (LocationUtil.isLocationResultEffective(bdLocation)) {
            onLocatedSuccess(bdLocation);
        } else {
            onLocatedFail(bdLocation);
        }
    }

    public abstract void onLocatedSuccess(@NonNull BDLocation bdLocation);
    public abstract void onLocatedFail(BDLocation bdLocation);

}

工具类:

public class LocationUtil {

    public static boolean isLocationResultEffective(BDLocation bdLocation) {
        return bdLocation != null
                && (bdLocation.getLocType() == BDLocation.TypeGpsLocation 
                || bdLocation.getLocType() == BDLocation.TypeNetWorkLocation);
    }

}

使用方法:

RxLocation.get().locate(this)
                .subscribe(new LocationSubscriber() {
                    @Override
                    public void onLocatedSuccess(@NonNull BDLocation bdLocation) {
                        //定位成功
                    }

                    @Override
                    public void onLocatedFail(BDLocation bdLocation) {
                        //定位失败
                    }
                });

这样简单的封装了一下,就可以把原回调模式的接口改造成RxJava的形式了,就可以使用RxJava的特性对数据流进行处理。是不是很简单 ?一起动手改造吧,如果你项目里已经引入了RxJava,那么很多地方都可以重构成RxJava的形式,如果你有其他的想法欢迎留言分享。

 

 

>> 转载请注明来源:当百度定位遇上 RxJava

评论

  • yorkyu回复

    改造是可以,线程变换起作用吗?

    • Dorae_min回复

      百度定位本身就不会阻塞线程,执行结果当然可以转到新线程中。

  • Marno回复

    试试去

  • 苌蓊芪回复

    使用rx封装过之后,会出现 LocationAuthManager Authentication Error errorcode = 200 , msg = {“status”:200,”message”:”APP不存在”},不知道是什么原因

    • pqpo回复

      不用 RxJava 封装就没问题?这个是百度 API 后台报的错。

      • 苌蓊芪回复

        可能是百度新的sdk(7.1)的问题,退回到前一版之后就没有这个报错了,rx封装后看上去确实是爽多了🙏

发表评论