当百度定位遇上 RxJava

2,161 阅读2分钟
原文链接: qlm.pw

在项目中引入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 locate(Context context) {
        return Observable.create(new LocationOnSubscribe(context));
    }

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

}

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

立即定位:

public class LocationOnSubscribe implements Observable.OnSubscribe {

    private final Context context;

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

    @Override
    public void call(final Subscriber 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 {

    private final Context context;

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

    @Override
    public void call(final Subscriber 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 {

    @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的形式,如果你有其他的想法欢迎留言分享。