インターネットに接続できない状況を処理したいと思います。通常、私は実行します:
ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();
( here )からリクエストをネットワークに送信する前に、インターネットに接続されていない場合はユーザーに通知します。
私が見たことから、Retrofitはこの状況を特に処理していません。インターネットに接続されていない場合は、タイムアウトを理由としてRetrofitError
を取得します。
Retrofitを使用して、この種のチェックをすべてのHTTPリクエストに組み込みたい場合、どうすればよいですか?または私はそれを全然するべきです。
ありがとう
アレックス
私がやったことは、リクエストを実行する前に接続を確認して例外をスローするカスタム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.8.0
から非推奨になりました
retrofitError.isNetworkError()
あなたは使わなければなりません
if (retrofitError.getKind() == RetrofitError.Kind.NETWORK)
{
}
処理できるエラーには複数のタイプがあります。
NETWORK
サーバーとの通信中にIOExceptionが発生しました。タイムアウト、接続なしなど.
CONVERSION
本文のシリアル化中に例外がスローされました。
HTTP
200以外のHTTPステータスコードがサーバーから受信されました。 502、503など...
UNEXPECTED
リクエストの実行中に内部エラーが発生しました。アプリケーションがクラッシュするように、この例外を再スローすることをお勧めします。
@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 ...]
}
}
}
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";
}
}
HttpリクエストからThrowable
エラーを受け取った場合、次のような方法でネットワークエラーかどうかを検出できます。
String getErrorMessage(Throwable e) {
RetrofitError retrofitError;
if (e instanceof RetrofitError) {
retrofitError = ((RetrofitError) e);
if (retrofitError.getKind() == RetrofitError.Kind.NETWORK) {
return "Network is down!";
}
}
}
UPDATE:これは、Retrofit 2ではなく、Retrofit 1でのみ機能すると言う必要があります。
これを行うだけで、次のような問題でも通知されます
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
} }
このコードを使用できます
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);
}