我想处理没有互联网连接的情况。通常我会跑:
ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
(来自here)在向网络发送请求之前,如果没有互联网连接,则通知用户。
从我看到的情况来看,Retrofit没有具体处理这种情况。如果没有互联网连接,我会以超时为原因获得RetrofitError
。
如果我想将这种检查结合到每个使用Retrofit的HTTP请求中,我应该怎么做?或者我应该这样做。
由于
亚历
答案 0 :(得分:58)
我最终做的是创建一个自定义Retrofit客户端,在客户端执行请求之前检查连接并抛出异常。
public class ConnectivityAwareUrlClient implements Client {
Logger log = LoggerFactory.getLogger(ConnectivityAwareUrlClient.class);
public ConnectivityAwareUrlClient(Client wrappedClient, NetworkConnectivityManager ncm) {
this.wrappedClient = wrappedClient;
this.ncm = ncm;
}
Client wrappedClient;
private NetworkConnectivityManager ncm;
@Override
public Response execute(Request request) throws IOException {
if (!ncm.isConnected()) {
log.debug("No connectivity %s ", request);
throw new NoConnectivityException("No connectivity");
}
return wrappedClient.execute(request);
}
}
然后在配置RestAdapter
RestAdapter.Builder().setEndpoint(serverHost)
.setClient(new ConnectivityAwareUrlClient(new OkHttpClient(), ...))
答案 1 :(得分:43)
自改造后1.8.0
已弃用
retrofitError.isNetworkError()
你必须使用
if (retrofitError.getKind() == RetrofitError.Kind.NETWORK)
{
}
您可以处理多种类型的错误:
NETWORK
与服务器通信时发生IOException,例如超时,没有连接等......
CONVERSION
在(de)序列化主体时抛出异常。
HTTP
从服务器收到非200 HTTP状态代码,例如502,503等...
UNEXPECTED
尝试执行请求时发生内部错误。最好重新抛出此异常,以便应用程序崩溃。
答案 2 :(得分:34)
@AlexV你确定当没有互联网连接时,RetrofitError包含超时作为原因(当调用getCause()时出现SocketTimeOutException)?
据我所知,当没有互联网连接时,RetrofitError包含一个ConnectionException作为原因。
如果您实施ErrorHandler,可以执行以下操作:
public class RetrofitErrorHandler implements ErrorHandler {
@Override
public Throwable handleError(RetrofitError cause) {
if (cause.isNetworkError()) {
if (cause.getCause() instanceof SocketTimeoutException) {
return new MyConnectionTimeoutException();
} else {
return new MyNoConnectionException();
}
} else {
[... do whatever you want if it's not a network error ...]
}
}
}
答案 3 :(得分:31)
使用Retrofit 2,我们使用OkHttp Interceptor实现在发送请求之前检查网络连接。如果没有网络,则根据需要抛出异常。
这允许人们在点击Retrofit之前专门处理网络连接问题。
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Response;
import io.reactivex.Observable
public class ConnectivityInterceptor implements Interceptor {
private boolean isNetworkActive;
public ConnectivityInterceptor(Observable<Boolean> isNetworkActive) {
isNetworkActive.subscribe(
_isNetworkActive -> this.isNetworkActive = _isNetworkActive,
_error -> Log.e("NetworkActive error " + _error.getMessage()));
}
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
if (!isNetworkActive) {
throw new NoConnectivityException();
}
else {
Response response = chain.proceed(chain.request());
return response;
}
}
}
public class NoConnectivityException extends IOException {
@Override
public String getMessage() {
return "No network available, please check your WiFi or Data connection";
}
}
答案 4 :(得分:3)
只要这样做,即使是
之类的问题,您也会收到通知UnknownHostException
SocketTimeoutException
和其他人。
@Override public void onFailure(Call<List<BrokenGitHubRepo>> call, Throwable t) {
if (t instanceof IOException) {
Toast.makeText(ErrorHandlingActivity.this, "this is an actual network failure :( inform the user and possibly retry", Toast.LENGTH_SHORT).show();
// logging probably not necessary
}
else {
Toast.makeText(ErrorHandlingActivity.this, "conversion issue! big problems :(", Toast.LENGTH_SHORT).show();
// todo log to some central bug tracking service
} }
答案 5 :(得分:1)
您可以使用此代码
<强> Response.java 强>
import com.google.gson.annotations.SerializedName;
/**
* Created by hackro on 19/01/17.
*/
public class Response {
@SerializedName("status")
public String status;
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
@SuppressWarnings({"unused", "used by Retrofit"})
public Response() {
}
public Response(String status) {
this.status = status;
}
}
<强> NetworkError.java 强>
import android.text.TextUtils;
import com.google.gson.Gson;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import retrofit2.adapter.rxjava.HttpException;
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
/**
* Created by hackro on 19/01/17.
*/
public class NetworkError extends Throwable {
public static final String DEFAULT_ERROR_MESSAGE = "Please try again.";
public static final String NETWORK_ERROR_MESSAGE = "No Internet Connection!";
private static final String ERROR_MESSAGE_HEADER = "Error Message";
private final Throwable error;
public NetworkError(Throwable e) {
super(e);
this.error = e;
}
public String getMessage() {
return error.getMessage();
}
public boolean isAuthFailure() {
return error instanceof HttpException &&
((HttpException) error).code() == HTTP_UNAUTHORIZED;
}
public boolean isResponseNull() {
return error instanceof HttpException && ((HttpException) error).response() == null;
}
public String getAppErrorMessage() {
if (this.error instanceof IOException) return NETWORK_ERROR_MESSAGE;
if (!(this.error instanceof HttpException)) return DEFAULT_ERROR_MESSAGE;
retrofit2.Response<?> response = ((HttpException) this.error).response();
if (response != null) {
String status = getJsonStringFromResponse(response);
if (!TextUtils.isEmpty(status)) return status;
Map<String, List<String>> headers = response.headers().toMultimap();
if (headers.containsKey(ERROR_MESSAGE_HEADER))
return headers.get(ERROR_MESSAGE_HEADER).get(0);
}
return DEFAULT_ERROR_MESSAGE;
}
protected String getJsonStringFromResponse(final retrofit2.Response<?> response) {
try {
String jsonString = response.errorBody().string();
Response errorResponse = new Gson().fromJson(jsonString, Response.class);
return errorResponse.status;
} catch (Exception e) {
return null;
}
}
public Throwable getError() {
return error;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NetworkError that = (NetworkError) o;
return error != null ? error.equals(that.error) : that.error == null;
}
@Override
public int hashCode() {
return error != null ? error.hashCode() : 0;
}
}
在您的方法中实施
@Override
public void onCompleted() {
super.onCompleted();
}
@Override
public void onError(Throwable e) {
super.onError(e);
networkError.setError(e);
Log.e("Error:",networkError.getAppErrorMessage());
}
@Override
public void onNext(Object obj) { super.onNext(obj);
}
答案 6 :(得分:0)
这就是我在API 29 & API 30
上所做的事情:
1。我创建了一个简单的WiFiService类,该类将保存ConnectivityManager:
class WifiService {
private lateinit var wifiManager: WifiManager
private lateinit var connectivityManager: ConnectivityManager
companion object {
val instance = WifiService()
}
fun initializeWithApplicationContext (context: Context) {
wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}
// Helper that detects if online
fun isOnline(): Boolean {
val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
if (capabilities != null) {
when {
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> return true
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> return true
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> return true
}
}
return false
}
}
2。创建ConnectivityInterceptor来检查互联网访问:
class ConnectivityInterceptor: Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
if (!WifiService.instance.isOnline()) {
throw IOException("No internet connection")
} else {
return chain.proceed(chain.request())
}
}
}
3。最后,在Retrofit2中使用它,如下所示:
class RestApi {
private val okHttpClient by lazy {
OkHttpClient.Builder()
.addInterceptor(ConnectivityInterceptor())
.build()
}
// Define all the retrofit clients
private val restApiClient by lazy {
Retrofit.Builder()
.baseUrl("http://localhost:10000")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
// ...
}