我有以下设置:
(new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
nameDoc = (TextView) findViewById(R.id.name);
iddoc = (TextView) findViewById(R.id.docId);
icdoc = (TextView) findViewById(R.id.icdoctor);
adddoc = (TextView) findViewById(R.id.addressdoc);
notel = (TextView) findViewById(R.id.noteldoc);
nameDoc.setText(docProf.getString("name"));
iddoc.setText(docProf.getString("id"));
icdoc.setText(docProf.getString("ic"));
adddoc.setText(docProf.getString("address"));
notel.setText(docProf.getString("noTel"));
}
});
我正在尝试处理我的服务器关闭并且用户获得连接超时异常的情况,这是我的日志记录:
final OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(5, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(5, TimeUnit.SECONDS);
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(ROOT)
.setClient(new OkClient(okHttpClient))
.setLogLevel(RestAdapter.LogLevel.FULL);
完整记录:http://pastebin.com/gscCGb7x
有没有办法将其转换为改装失败方法,以便我可以在那里处理它?</ p>
提前致谢!
答案 0 :(得分:41)
For Retrofit 2
在Web服务实例中定义一个侦听器:
public interface OnConnectionTimeoutListener {
void onConnectionTimeout();
}
向您的网络服务添加拦截器:
public WebServiceClient() {
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(10, TimeUnit.SECONDS);
client.setReadTimeout(30, TimeUnit.SECONDS);
client.interceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
return onOnIntercept(chain);
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
webService = retrofit.create(WebService.class);
}
使用try-catch块封闭您的拦截代码,并在发生异常时通知侦听器:
private Response onOnIntercept(Chain chain) throws IOException {
try {
Response response = chain.proceed(chain.request());
String content = UtilityMethods.convertResponseToString(response);
Log.d(TAG, lastCalledMethodName + " - " + content);
return response.newBuilder().body(ResponseBody.create(response.body().contentType(), content)).build();
}
catch (SocketTimeoutException exception) {
exception.printStackTrace();
if(listener != null)
listener.onConnectionTimeout();
}
return chain.proceed(chain.request());
}
<强>科特林强>
如果您想在Retrofit
中使用Kotlin
,请按以下步骤操作:
定义您的Retrofit界面:
interface GitHubApi {
@GET("/users/{userName}/repos")
fun repos(@Path("userName") userName: String): Call<List<Repo>>
}
实施您的服务:
class Api(...) {
private val baseUrl = "https://api.github.com"
private val api: GitHubApi
private fun loggingInterceptor(...): HttpLoggingInterceptor {...}
private fun okHttpBuilder(): OkHttpClient {...}
init {...}
fun repos(
userName: String,
onSuccess: (list: List<Repo>?) -> Unit,
onFailure: (message: String?) -> Unit): Future<Unit> {
return runAsync(api.repos(userName), onSuccess, onFailure)
}
private fun <T> runAsync(
call: retrofit2.Call<T>,
onSuccess: (T?) -> Unit,
onFailure: (message: String?) -> Unit) : Future<Unit> {
return doAsync {
try {
val response = call.execute()
when {
response.isSuccessful -> response.body()?.let {
onSuccess(it)
}
else -> {
onFailure(response.raw().message())
}
}
} catch (e: IOException) {
if (e is SocketTimeoutException) {
onFailure("Response time out!")
} else {
onFailure(e.message)
}
}
}
}
}
在您想要的地方致电您的服务:
Api().repos("olcayertas",
onSuccess = {
Log.d("MainActivity", "Response:\n" + toJson(it))
},
onFailure = {
Log.e("MainActivity", "Error: $it")
})
您可以在runAsync
函数中处理所需的任何异常。
您可以获得完整的示例here。
答案 1 :(得分:29)
@Override
public void onFailure(Call call, Throwable t) {
if(t instanceof SocketTimeoutException){
message = "Socket Time out. Please try again.";
}
}
答案 2 :(得分:3)
显然,异常会被包装到RetrofitException中,因此您可以在失败方法中处理它。
答案 3 :(得分:3)
它有点复杂。使用Retrofit,您可以进行同步或异步的API调用。
如果您的端点返回void并且有回调,则它是异步的。 如果它返回某些内容并且没有回调,则它是同步的。
对于异步调用,您可以在回调的onFailure(...)
方法中获得此异常。
对于同步通话,你根本不会得到它,除非你用try / catch包裹你的电话。
try {
// your synchronous call goes here
} catch (RetrofitError error) {
// handle errors
}
更新:上述答案适用于Retrofit 1.9。 Retrofit 2.0已经改变了很多。如果您想知道Retrofit 2.0中现在的工作方式,本文提供了一些指示http://inthecheesefactory.com/blog/retrofit-2.0/en
答案 4 :(得分:0)
如果有人带着科特琳/协程来到这里遇到同样的问题,请将错误处理程序添加到协程范围:
CoroutineScope(Dispatchers.IO).launch(handler) {
处理程序本身看起来像:
val handler = CoroutineExceptionHandler { _, exception ->
Log.t("Network", "Caught $exception")
}
答案 5 :(得分:0)
科特林
如果要在Retrofit
中使用Kotlin
,请执行以下步骤:
定义您的改造界面:
interface GitHubApi {
@GET("/users/{userName}/repos")
fun repos(@Path("userName") userName: String): Call<List<Repo>>
}
实施您的服务:
class Api(...) {
private val baseUrl = "https://api.github.com"
private val api: GitHubApi
private fun loggingInterceptor(...): HttpLoggingInterceptor {...}
private fun okHttpBuilder(): OkHttpClient {...}
init {...}
fun repos(
userName: String,
onSuccess: (list: List<Repo>?) -> Unit,
onFailure: (message: String?) -> Unit): Future<Unit> {
return runAsync(api.repos(userName), onSuccess, onFailure)
}
private fun <T> runAsync(
call: retrofit2.Call<T>,
onSuccess: (T?) -> Unit,
onFailure: (message: String?) -> Unit) : Future<Unit> {
return doAsync {
try {
val response = call.execute()
when {
response.isSuccessful -> response.body()?.let {
onSuccess(it)
}
else -> {
onFailure(response.raw().message())
}
}
} catch (e: IOException) {
if (e is SocketTimeoutException) {
onFailure("Response time out!")
} else {
onFailure(e.message)
}
}
}
}
}
在需要的地方致电服务
Api().repos("olcayertas",
onSuccess = {
Log.d("MainActivity", "Response:\n" + toJson(it))
},
onFailure = {
Log.e("MainActivity", "Error: $it")
})
您可以在runAsync
函数中处理所需的任何异常。
您可以获得完整的示例here。
答案 6 :(得分:0)
我发布此消息有两个原因:
因此,这是我在 Kotlin 中提出的解决方案。它的灵感来自the answer提供的@Olcay Ertaş,并与Google's recommended architecture结合用于Android应用。
创建一个TimeoutInterceptor
界面:
interface TimeoutInterceptor : Interceptor
实现TimeoutInterceptor
界面:
class TimeoutInterceptorImpl : TimeoutInterceptor {
override fun intercept(chain: Interceptor.Chain): Response {
if (isConnectionTimedOut(chain))
throw SocketTimeoutException()
return chain.proceed(chain.request())
}
private fun isConnectionTimedOut(chain: Interceptor.Chain): Boolean {
try {
val response = chain.proceed(chain.request())
val content = response.toString()
response.close()
Log.d(tag, "isConnectionTimedOut() => $content")
} catch (e: SocketTimeoutException) {
return true
}
return false
}
}
在ApiService
界面中,将TimeoutInterceptor
添加到OkHttpClient
构建器中:
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(requestInterceptor)
// Add timeout interceptor
.addInterceptor(timeoutInterceptor)
// Set a 5s custom connect timout
.connectTimeout(5, TimeUnit.SECONDS)
.build()
您可能已经注意到,可以设置自定义连接超时。否则,根据documentation,它会保留10秒作为默认值。
创建一个枚举类ConnectionState
。它将提供一个枚举常量对象CONNECTION_TIMEOUT
,该对象将进一步用于将适当的连接(或API调用)状态从EntityNetworkDataSource
类传递到View类(如果您遵循Google's MVVM pattern):
enum class ConnectionState {
CONNECTED, NOT_CONNECTED, CONNECTION_TIMEOUT
}
假设您的EntityNetworkDataSource
界面看起来像这样:
interface EntityNetworkDataSource {
val fetchedEntity: LiveData<Entity>
// Wrap your ConnectionState object in LiveData in order to be able to observe it in the View
val connectionState: LiveData<ConnectionState>
// Fetch `Entity` object from the network
suspend fun fetchEntity(id: Int)
}
在EntityNetworkDataSource
实现类中,您可以在SocketTimeoutException
实现内部正确捕获fetchEntity(id: Int)
,如下所示:
class EntityNetworkDataSourceImpl(
private val apiService: ApiService
) : EntityNetworkDataSource {
private val _fetchedEntity = MutableLiveData<Entity>()
override val fetchedEntity: LiveData<Entity>
get() = _fetchedEntity
// We want to keep our MutableLiveData private because they can be changed.
// So we want to be able to update them only from the inside of this class
private val _connectionState = MutableLiveData<ConnectionState>()
override val connectionState: LiveData<ConnectionState>
get() = _connectionState
override suspend fun fetchEntity(id: Int) {
try {
val fetchedEntity = apiService
.getEntity(id)
.await()
// Convey the updated connection state to the observer View
_connectionState.postValue(ConnectionState.CONNECTED)
_fetchedEntity.postValue(fetchedEntity)
} catch (e: SocketTimeoutException) {
Log.e(tag, "Connection timeout. ", e)
// Catch the SocketTimeoutException and post the updated connection state to the observer View
_connectionState.postValue(ConnectionState.CONNECTION_TIMEOUT)
}
}
}
相同的原理适用于您要拦截和捕获的任何连接异常。
答案 7 :(得分:0)
没有一个答案对我有用,但它们引导我走向正确的方向。这是我在 Kotlin 中的做法:
class ErrorInterceptor : Interceptor {
override fun intercept(chain: Chain): Response = chain.run {
try {
proceed(
request()
.newBuilder()
.build()
)
} catch (e: Exception) {
var msg = ""
val errorCode: Int
when (e) {
is SocketTimeoutException -> {
msg = // string message //
errorCode = // some int //
}
// Add additional error catching here //
}
return Response.Builder()
.request(request())
.protocol(Protocol.HTTP_1_1)
.code(errorCode)
.message(msg)
.body("{${e}}".toResponseBody(null)).build()
}
}
}
okHttpClient.newBuilder()
.addInterceptor(ErrorInterceptor())
.connectTimeout(10, TimeUnit.SECONDS)
// ... //
.build()
然后在我的存储库层中是这样的:
suspend fun makeAPIRequest(): Resource<ApiResponse> {
return withContext(ioDispatcher) {
var response: Response<ApiResponse>? = null
try {
response = getResponse()
// Do additional ops here //
} catch (e: Exception) {
// Exceptions caught in ErrorInterceptor will propagate here
}
}
}