当百度定位遇上 RxJava
在项目中引入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封装后看上去确实是爽多了