Android: Как обрабатывать сообщение об ошибке с сервера с помощью Volley?
Я использую Volley для моего приложения Android для извлечения данных с моего сервера. Он работает хорошо, кроме случаев, когда обрабатывается ошибка с моего сервера. Мой сервер отправляет этот ответ, когда есть ошибка:
{
"status": 400,
"message": "Errors (2): A name is required- Julien is already used. Not creating."
}
Моя цель - получить сообщение, а затем отобразить его в Toast
. Я сделал несколько примеров, как это сделать, но это не сработает.
Есть мой прослушиватель ошибок:
public void onErrorResponse(VolleyError error) {
int statusCode = error.networkResponse.statusCode;
NetworkResponse response = error.networkResponse;
Log.d("testerror",""+statusCode+" "+response.data);
// Handle your error types accordingly.For Timeout & No connection error, you can show 'retry' button.
// For AuthFailure, you can re login with user credentials.
// For ClientError, 400 & 401, Errors happening on client side when sending api request.
// In this case you can check how client is forming the api and debug accordingly.
// For ServerError 5xx, you can do retry or handle accordingly.
if( error instanceof NetworkError) {
} else if( error instanceof ClientError) {
} else if( error instanceof ServerError) {
} else if( error instanceof AuthFailureError) {
} else if( error instanceof ParseError) {
} else if( error instanceof NoConnectionError) {
} else if( error instanceof TimeoutError) {
}
showProgress(false);
mPasswordView.setError(getString(R.string.error_incorrect_password));
mPasswordView.requestFocus();
}
И вот результат моего отладчика: testerror: 400 [B @430b8d60
EDIT: Кроме того, моя error.getMessage() имеет значение null.
Поэтому я не понимаю, почему моя переменная response.data не является ответом от моего сервера.
Если кто-то знает, как я могу получить сообщение с моего сервера, это будет круто.
спасибо,
Ответы
Ответ 1
Я реализовал нечто похожее на это, и это относительно просто. В вашем лог-сообщении печатается то, что похоже на тарабарщину, потому что response.data
- действительно байтовый массив, а не String
. Кроме того, VolleyError
на самом деле просто расширенный Exception
, поэтому Exception.getMessage() скорее всего не вернет то, что вы ищете, если вы не переопределите методы синтаксического анализа для разбора вашего VolleyError
в расширенном классе Request
. На самом деле основным способом справиться с этим было бы сделать что-то вроде:
//In your extended request class
@Override
protected VolleyError parseNetworkError(VolleyError volleyError){
if(volleyError.networkResponse != null && volleyError.networkResponse.data != null){
VolleyError error = new VolleyError(new String(volleyError.networkResponse.data));
volleyError = error;
}
return volleyError;
}
}
Если вы добавите это в расширенные классы Request
, ваш getMessage()
должен хотя бы не возвращать значение null. Я обычно не беспокоюсь об этом, так как достаточно легко сделать все это из вашего метода onErrorResponse(VolleyError e)
.
Вы должны использовать библиотеку JSON для упрощения работы - например, я использую Gson или вы можете использовать Apache JSONObject
, который не должен требовать дополнительного внешняя библиотека. Первый шаг - получить ответ JSON, посланный с вашего сервера как String
(аналогично тому, что я только что продемонстрировал), затем вы можете преобразовать его в JSONObject (используя apache JSONObject
и JsonArray
s или другую библиотеку по вашему выбору) или просто проанализируйте String
самостоятельно. После этого вам просто нужно отобразить Toast
.
Вот пример кода для начала работы:
public void onErrorResponse(VolleyError error) {
String json = null;
NetworkResponse response = error.networkResponse;
if(response != null && response.data != null){
switch(response.statusCode){
case 400:
json = new String(response.data);
json = trimMessage(json, "message");
if(json != null) displayMessage(json);
break;
}
//Additional cases
}
}
public String trimMessage(String json, String key){
String trimmedString = null;
try{
JSONObject obj = new JSONObject(json);
trimmedString = obj.getString(key);
} catch(JSONException e){
e.printStackTrace();
return null;
}
return trimmedString;
}
//Somewhere that has access to a context
public void displayMessage(String toastString){
Toast.makeText(context, toastString, Toast.LENGTH_LONG).show();
}
Ответ 2
попробуйте этот класс для обработки всех erros
public class VolleyErrorHelper {
/**
* Returns appropriate message which is to be displayed to the user
* against the specified error object.
*
* @param error
* @param context
* @return
*/
public static String getMessage (Object error , Context context){
if(error instanceof TimeoutError){
return context.getResources().getString(R.string.timeout);
}else if (isServerProblem(error)){
return handleServerError(error ,context);
}else if(isNetworkProblem(error)){
return context.getResources().getString(R.string.nointernet);
}
return context.getResources().getString(R.string.generic_error);
}
private static String handleServerError(Object error, Context context) {
VolleyError er = (VolleyError)error;
NetworkResponse response = er.networkResponse;
if(response != null){
switch (response.statusCode){
case 404:
case 422:
case 401:
try {
// server might return error like this { "error": "Some error occured" }
// Use "Gson" to parse the result
HashMap<String, String> result = new Gson().fromJson(new String(response.data),
new TypeToken<Map<String, String>>() {
}.getType());
if (result != null && result.containsKey("error")) {
return result.get("error");
}
} catch (Exception e) {
e.printStackTrace();
}
// invalid request
return ((VolleyError) error).getMessage();
default:
return context.getResources().getString(R.string.timeout);
}
}
return context.getResources().getString(R.string.generic_error);
}
private static boolean isServerProblem(Object error) {
return (error instanceof ServerError || error instanceof AuthFailureError);
}
private static boolean isNetworkProblem (Object error){
return (error instanceof NetworkError || error instanceof NoConnectionError);
}