Android RxJava NetworkOnMainThread订阅时发生异常
我试图调用API并将数据添加到我的LiveData中,但在订阅之后,我在OnError中获得MainThreadException。尝试了不同的调度程序,但没有成功。从onError添加stacktraceAndroid RxJava NetworkOnMainThread订阅时发生异常,android,rx-java,rx-java2,Android,Rx Java,Rx Java2,我试图调用API并将数据添加到我的LiveData中,但在订阅之后,我在OnError中获得MainThreadException。尝试了不同的调度程序,但没有成功。从onError添加stacktrace private void pullLocation(){ myLocationService.getLocation() .flatMapSingle(new Function<Location, Single<DistanceResponseM
private void pullLocation(){
myLocationService.getLocation()
.flatMapSingle(new Function<Location, Single<DistanceResponseModel>>() {
@Override
public Single<DistanceResponseModel> apply(@NonNull Location location) throws Exception {
return distanceRepository.distanceResponseAPI(location.getLatitude() + "," + location.getLongitude(), getDestinations(), "my_google_api_key");
}
})
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Subscriber<DistanceResponseModel>() {
@Override
public void onSubscribe(Subscription s) {
Log.d(TAG, "onSubscribe in DistanceViewModel called. ");
}
@Override
public void onNext(DistanceResponseModel distanceResponseModel) {
distanceLiveData.postValue(distanceResponseModel);
Log.d(TAG, "onNext in DistanceViewModel called. ");
}
@Override
public void onError(Throwable t) {
Log.e("YOUR_APP_LOG_TAG", "I got an error:", t);
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete in DistanceViewModel called. ");
}
});
}
这是我得到的位置:
public class MyLocationServiceClass implements MyLocationService {
PublishProcessor<Location> stream = PublishProcessor.create();
LocationListener listener = new LocationListener() {
@Override
public void onLocationChanged(@NonNull Location location) {
stream.onNext(location);
Log.d(TAG, "onLocationChanged: stream.onNext(location) called");
}
@Override
public void onProviderEnabled(@NonNull String provider) {
}
@Override
public void onProviderDisabled(@NonNull String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
private LocationManager locationManager;
private boolean flag;
private Context context;
public MyLocationServiceClass(Context context, LocationManager locationManager, boolean flag) {
this.context = context;
this.locationManager = locationManager;
this.flag = flag;
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onStart() {
if (flag) {
start();
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onStop() {
locationManager.removeUpdates(listener);
}
@Override
public Flowable<Location> getLocation() {
return stream.hide();
}
@Override
public void start() {
long minTimeMs = 10000;
float minDistanceM = 5.5F;
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
Log.d(TAG, "start(): requestLocationUpdates called.");
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTimeMs, minDistanceM, listener);
}
@Override
public void updatePermission(boolean newState) {
flag = newState;
}
public interface MyLocationService extends LifecycleObserver {
Flowable<Location> getLocation();
void start();
void updatePermission(boolean newState);
}
公共类MyLocationServiceClass实现MyLocationService{
PublishProcessor流=PublishProcessor.create();
LocationListener=新建LocationListener(){
@凌驾
public void onLocationChanged(@NonNull Location){
stream.onNext(位置);
Log.d(标记“onLocationChanged:stream.onNext(location)called”);
}
@凌驾
public void onProviderEnabled(@NonNull字符串提供程序){
}
@凌驾
public void onProviderDisabled(@NonNull字符串提供程序){
}
@凌驾
public void onStatusChanged(字符串提供程序、int状态、Bundle extra){
}
};
私人场所经理场所经理;
私有布尔标志;
私人语境;
公共MyLocationServiceClass(上下文上下文、LocationManager LocationManager、布尔标志){
this.context=上下文;
this.locationManager=locationManager;
this.flag=flag;
}
@onLiFeCycleeEvent(Lifecycle.Event.ON_START)
void onStart(){
国际单项体育联合会(旗){
start();
}
}
@onLiFeCycleeEvent(Lifecycle.Event.ON_STOP)
void onStop(){
locationManager.RemoveUpdate(侦听器);
}
@凌驾
公共可流动getLocation(){
返回stream.hide();
}
@凌驾
公开作废开始(){
长最小时间=10000;
浮动距离M=5.5F;
if(ActivityCompat.checkSelfPermission(context,Manifest.permission.ACCESS\u FINE\u LOCATION)!=PackageManager.permission\u已授予和&ActivityCompat.checkSelfPermission(context,Manifest.permission.ACCESS\u LOCATION)!=PackageManager.permission\u已授予){
返回;
}
d(标记“start():requestLocationUpdates called.”);
locationManager.RequestLocationUpdate(locationManager.GPS_提供程序、Mintimes、MindStatancem、侦听器);
}
@凌驾
public void updatePermission(布尔newState){
flag=新闻状态;
}
公共接口MyLocationService扩展LifecycleObserver{
可流动的getLocation();
void start();
void updatePermission(布尔newState);
}
你知道会是什么吗?如果你想知道更多细节,请告诉我。希望这能有所帮助
带完整代码的回购:问题
调用distanceRepository.distanceResponseAPI(location.getLatitude()+,“+location.getLatitude(),getDestinations(),“my_google_api_key”)
时,onError(NetworkOnMainThreadException)会传播到订阅服务器
为什么会抛出异常?
禁止在UI Eventloop上执行网络请求,以免阻塞UI
为什么订阅没有帮助?
subscribeOn
调用给定调度程序上游操作符的subscribeActual方法。在您的情况下,从IO调度程序中的工作线程调用subscribe forflatMapSingle
操作符。flatMapSingle
在同一线程上调用myLocationService.getLocation()
正如您在stacktrace中看到的,从getLocation
返回的onNext from source observable是从UI线程发出的
at io.reactivex.processors.PublishProcessor$PublishSubscription.onNext(PublishProcessor.java:361)
at io.reactivex.processors.PublishProcessor.onNext(PublishProcessor.java:244)
at com.example.compass.viewModels.MyLocationServiceClass$1.onLocationChanged(MyLocationServiceClass.java:35)
at android.location.LocationManager$ListenerTransport._handleMessage(LocationManager.java:292)
at android.location.LocationManager$ListenerTransport.-wrap0(Unknown Source:0)
at android.location.LocationManager$ListenerTransport$1.handleMessage(LocationManager.java:237)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
该值通过调用线程(UI线程)上的onNext发出,因为回调是从UI线程调用的。flatMapSingle
操作符也在调用UI线程上调用。它订阅lambda返回的Single
,并在调用线程上订阅。因此UI线程调用UI线程上的网络请求,异常由ndroid运行时。SubscribeOn
不确保onNext在给定的调度程序上处于下游。它只确保订阅在此线程中发生。在您的情况下,您的源可观察对象将在UI线程上收到安卓运行时的通知
解决方案
在myLocationService.getLocation()之后使用observeOn
以将线程从一个操作符切换到另一个操作符。observeOn
确保onNext
调用下游发生在给定的调度程序上。因此,flatMapSingle
中的内部流订阅将发生在给定的调度程序工作线程上,而不是ui线程上。您也可以应用在flatMapSingle
中的Single
上订阅。这将确保网络调用将在给定的调度程序工作线程上发生
.flatMapSingle(new Function<Location, Single<DistanceResponseModel>>() {
@Override
public Single<DistanceResponseModel> apply(@NonNull Location location) throws Exception {
return distanceRepository.distanceResponseAPI(location.getLatitude() + "," + location.getLongitude(), getDestinations(), "my_google_api_key")
.subscribeOn(Schedulers.io());
}
})
.flatMapSingle(新函数(){
@凌驾
公共单应用(@NonNull Location)引发异常{
返回distanceRepository.distanceResponseAPI(location.getLatitude()+”、“+location.getLatitude()、getDestinations()、“my_google_api_key”)
.subscribeOn(Schedulers.io());
}
})
进一步阅读
你能发布stacktrace吗?好吧,我的代码已经编译好了,所以没有错误。但是,当我记录一个错误时,抛出了NetworkOnMainThreadException。不确定粘贴整个日志是否有用。查看抛出异常的位置会很有趣。记录stacktrace,而不仅仅是异常的名称。而在这里,您还可以包括getLocation()
的关键部分。请尝试distanceRepository.distanceResponseAPI(…).subscribeOn(Schedulers.io())
直接。在flatMap
之后应用它不会影响设置中的lambda。@akarnokd,该死的。我太晚了。是的,似乎flatMapSingle是问题的根本原因(例如stacktrace:可流动。可流动flatMapSingle
)
.flatMapSingle(new Function<Location, Single<DistanceResponseModel>>() {
@Override
public Single<DistanceResponseModel> apply(@NonNull Location location) throws Exception {
return distanceRepository.distanceResponseAPI(location.getLatitude() + "," + location.getLongitude(), getDestinations(), "my_google_api_key")
.subscribeOn(Schedulers.io());
}
})