我应该如何处理“没有互联网连接”与改造的 Android

我喜欢处理没有网络连接的情况,通常我会跑:

ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);


NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();

(从 给你) ,然后发送请求到网络,并通知用户,如果没有互联网连接。

在我看来,“翻新”并没有特别处理这种情况。如果没有互联网连接,我只会得到 RetrofitError与超时作为一个理由。

如果我想在每个 HTTP 请求中加入这种检查,我应该怎么做?或者我应该这么做。

谢谢

亚历克斯

109605 次浏览

@ AlexV 当没有互联网连接时,您是否确定逆转错误包含超时作为原因(当调用 getCause ()时,SocketTimeOutException) ?

据我所知,当没有互联网连接时,逆转错误包含一个 ConnectionException 作为原因。

如果你实现一个 错误处理程序,你可以这样做:

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 ...]
}
}


}

最后,我创建了一个自定义便携客户机,它在执行请求之前检查连接并抛出异常。

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)
{


}

您可以处理多种类型的错误:

与服务器通信时发生 IOException,例如超时、无连接等。

在(反)序列化主体时引发异常。

收到来自服务器的非200个 HTTP状态码,例如502,503等。

执行请求时发生内部错误。最佳做法是重新引发此异常,以使应用程序崩溃。

翻新1

当您从 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!";
}
}
}

在便携2中,我们使用 OkHttp 拦截器实现在发送请求之前检查网络连接。如果没有网络,则适当地引发异常。

这使得人们可以在点击“修复”之前专门处理网络连接问题。

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";
}
}

你可以用这个代码

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);
}

只要这样做,即使是像

未知 HostException

,

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
} }

以下是我在 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. 在加装2中使用如下:

  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()
}


// ...
}

4. 最后初始化 WifiService:

class MainApplication: Application() {
companion object {
lateinit var instance:  MainApplication
}


override fun onCreate() {
super.onCreate()
instance = this


setupServices()
}


private fun setupServices() {
WifiService.instance.initializeWithApplicationContext(this)
}
}