在我的Android应用程序中,我使用Retrofit 2.2和RxJava 2进行网络调用。当设备连接到网络时,一切都很好。 当我禁用移动和WiFi网络时,应用程序崩溃。 奇怪的是我可以正确处理错误但是应用程序仍然会崩溃。
这是Retrofit的API接口:
public interface BackendApi {
@GET("v1/users/{uuid}")
Observable<User> getUser(@Path("uuid") String userUuid);
}
以下方法返回一个Observable,它将在我的视图模型中订阅。
@Override
public Observable<User> getUser(@NonNull final UUID id) {
return api.getUser(id.toString()).map(user -> mapUser(user));
}
在视图模型中,我订阅了Observable:
compositeDisposable.add(userService.getUser(userId)
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onGetUser, this::onGetUserError));
以下行显示了错误处理方法
private void onGetUserError(final Throwable throwable) {
log.error("onGetUserError, getting user failed because of {}",
throwable.getCause());
if (isViewAttached()) {
getView().showUserLoginOrRegisterError();
}
}
问题是,当我从移动和wifi连接断开设备时,onGetUserError()方法被正确调用,但无论如何都有一个未处理的异常导致我的应用程序崩溃。
这里是完整的堆栈跟踪:
https://gist.github.com/anonymous/859ab3811a3ca5c63998a40b877c41bb
我不知道如何摆脱这些崩溃!!
此致 马丁
---------- update 03.04.2017 --------- 还有另一个神秘...... 在三星Galaxy(S5)上,堆栈跟踪是相同的,但它是在我的错误处理程序方法中打印的!所以我能够正确捕获和处理异常。
04-03 12:36:46.014 12078-12078/at.xxxx.yyyyapp
E/at.xxxx.yyyyapp.ui.startup.viewmodel.StartupViewModelImpl:
onGetUserError, getting user failed because of {}
android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No
address associated with hostname)
at libcore.io.Posix.android_getaddrinfo(Native Method)
at libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:55)
at java.net.InetAddress.lookupHostByName(InetAddress.java:451)
at java.net.InetAddress.getAllByNameImpl(InetAddress.java:252)
at java.net.InetAddress.getAllByName(InetAddress.java:215)
at okhttp3.Dns$1.lookup(Dns.java:39)
at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelec
tor.java:170)
at
okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.java:136)
在我的其他测试设备(Nexus 5和6P)上调用了我的错误处理程序方法,但应用程序无论如何都会崩溃。
我不知道如何解决这个问题!
答案 0 :(得分:1)
我遇到了完全相同的问题并且刚刚解决了。
当收到响应时,我没有实现onError处理,这是原因。
someObservable
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Response>() {
@Override public void onSubscribe(Disposable d) {
disposables.add(d);
}
@Override public void onNext(Response response) {
}
@Override public void onError(Throwable e) {
// implement this!!!
}
@Override public void onComplete() {
}
});
希望这会奏效。
答案 1 :(得分:0)
您可以在调用API方法之前检查网络连接。
slime-v2.19
将其用作
public static boolean isInternetAvailable(Context context) {
ConnectivityManager mConMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
return mConMgr.getActiveNetworkInfo() != null
&& mConMgr.getActiveNetworkInfo().isAvailable()
&& mConMgr.getActiveNetworkInfo().isConnected();
}
这将是这个问题最简单的解决方案。 快乐的编码!
答案 2 :(得分:0)
嗯,首先,当您没有连接到互联网时,您不应该发送任何请求。
其次,你应该用.flatMap.
包裹你的api电话你可以在这里找到一个例子,如果你从api调用中得到任何异常,这将抓住它。
示例:
public Observable<User> getUser(@NonNull final UUID id) {
return Observable.fromCallable(new Callable<User>() {
@Override
public User call() throws Exception {
return api.getUser(id.toString());
}
}).map(user -> mapUser(user));
}
答案 3 :(得分:0)
我遇到了这样一个问题:如果服务器关闭或没有网络连接,改造会崩溃。
我不得不将 addCallAdapterFactory
添加到改造客户端。有很多关于如何添加自定义调用适配器工厂的教程。
Retrofit.Builder()
.baseUrl(BuildConfig.API_URL)
.addCallAdapterFactory(NetworkResponseAdapterFactory())
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()