После долгой борьбы с дженериками и стиранием типов я, наконец, сделал это.
Итак, я публикую это для тех, у кого такая же проблема, как у меня, и кому нужно решение, не волнуясь.
Мои ErrorEntity и SuccessfulEntity остались прежними, но я создал новый интерфейс RepositoryListener, например:
public interface RepositoryListener {
public abstract void onErrorResponse(int code, String details);
public abstract void onSuccessfulResponse(int code, Object obj);
public abstract void onSuccessfulResponse2(int code, List<Object> obj);
}
Затем я создал класс VolleyRestClient, например:
public class VolleyRestClient extends RestClient {
private final DefaultRetryPolicy mRetryPolicy;
private final RequestQueue mQueue;
private final Gson gson = new Gson();
public VolleyRestClient(Context context) {
// Default retry policy
mRetryPolicy = new DefaultRetryPolicy(2000, 3, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
mQueue = Volley.newRequestQueue(context);
}
public RequestQueue getQueue() {
// Method to push requests for image download
return mQueue;
}
@Override
public void GET(boolean obj, boolean needAuth, String url, Type type,
RepositoryListener listener) {
// Choose which listener to construct
Response.Listener<myResponse> mListener = obj ?
// This uses objects
makeSuccessfulListener(listener, type) :
// This uses list of objects
makeSuccessfulListener2(listener, type);
myRequest mRequest =
new myRequest(Request.Method.GET, needAuth, url,
mListener, makeErrorListener(listener));
mRequest.setRetryPolicy(mRetryPolicy);
mQueue.add(mRequest);
}
@Override
public void POST(boolean needAuth, String url, String body, Type type, RepositoryListener listener) {
myRequest mRequest = new myRequest(Request.Method.POST, needAuth, url, body,
makeSuccessfulListener(listener, type), makeErrorListener(listener));
mRequest.setRetryPolicy(mRetryPolicy);
mQueue.add(mRequest);
}
@Override
public void DELETE(boolean needAuth, String url, Type type, RepositoryListener listener) {
myRequest mRequest =
new myRequest(Request.Method.DELETE, needAuth, url,
makeSuccessfulListener(listener, type), makeErrorListener(listener));
mRequest.setRetryPolicy(mRetryPolicy);
mQueue.add(mRequest);
}
private Response.Listener<myRequest> makeSuccessfulListener
(final RepositoryListener listener, final Type type) {
// TODO: test this method and implement lists
if (listener == null) {
return null;
} else {
return new Response.Listener<myRequest>() {
@Override
public void onResponse(myRequest response) {
SuccessfulEntity<Object> obj = gson.fromJson(response.getBody(), type);
listener.onSuccessfulResponse(response.getCode(), obj.getData());
}
};
}
}
private Response.Listener<myRequest> makeSuccessfulListener2
(final RepositoryListener listener, final Type type) {
// TODO: test lists
if (listener == null) {
return null;
} else {
return new Response.Listener<myRequest>() {
@Override
public void onResponse(myReqyest response) {
SuccessfulEntity<List<Object>> obj = gson.fromJson(response.getBody(), type);
listener.onSuccessfulResponse2(response.getCode(), obj.getData());
}
};
}
}
private Response.ErrorListener makeErrorListener(final RepositoryListener listener) {
return new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
try {
String jError = new String(error.networkResponse.data);
ErrorEntity mError = gson.fromJson(jError, ErrorEntity.class);
// Invoke listener closure
listener.onErrorResponse(error.networkResponse.statusCode, mError.getDetails());
} catch (Exception e) {
listener.onErrorResponse(404, e.getMessage());
}
}
};
}
}
Это очень зависит от моих потребностей, но я объясню общую концепцию.
Итак, у меня есть пользовательский запрос, как объясняется в моем вопросе, и я хочу проанализировать его на правильный тип данных.
Чтобы быть более конкретным, я мог бы иметь данные JSONArray только для запросов GET (элементы с разбивкой на страницы и т. д.), поэтому мне нужно найти способ различать эти два случая (конечно, я знаю, в каких случаях я получу список или объект).
Мы не можем просто создать POJO из Json внутри универсального класса, используя его тип (потому что Java Type Erasure), поэтому нам нужен тип объекта upfront.
Но что мы можем сделать, так это:
в нашем пользовательском запросе на parseNetworkResponse сделайте что-то вроде этого:
@Override
protected Response<myResponse> parseNetworkResponse(NetworkResponse response) {
try {
// Using server charset
myResponse mResponse = new myResponse();
mResponse.setCode(response.statusCode);
mResponse.setBody(new String(response.data,
HttpHeaderParser.parseCharset(response.headers)));
// Return new response
return Response.success(mResponse, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
// Normally use 'utf-8'
return Response.error(new ParseError(e));
}
}
Другими словами, скопируйте необработанное текстовое тело ответа в новый объект myResponse;
Тело ответа будет в конечном итоге проанализировано в VolleyRestClient с соответствующим типом, переданным в качестве аргумента GET/DELETE/POST;
makeSuccessfulListener и makeSuccessfulListener2 создают Response.Listener из RepositoryListener, который имеет 3 переопределяемых метода: onSuccessfulResponse для данных объектов, onSuccessfulResponse2< /em> для списка данных объектов, onErrorResponse для ошибок 4XX/5XX;
- Our data object/list will be parsed to more generics type (List and Object) and then passed to our custom listener RepositoryListener.
Полный пример для этого подхода:
public void getNewLogin(String nickname, String password,
final TextView author, final TextView title, final TextView text) {
String json =
(new StringBuilder()
.append("{ \"nickname\": \"")
.append(nickname)
.append("\", \"password\": \"")
.append(password)
.append("\" }")).toString();
mRest.POST(false, "http://192.168.0.104:8000/api/session", json,
new TypeToken<SuccessfulEntity<Login>>(){}.getType(),
new RepositoryListener() {
@Override
public void onSuccessfulResponse2(int code, List<Object> obj) {
// Nothing happens here
}
@Override
public void onSuccessfulResponse(int code, Object obj) {
UserSession mInstance = UserSession.getInstance(null);
Login newLogin = (Login) obj;
title.setText(newLogin.getToken());
mInstance.setToken(newLogin.getToken());
Log.i("onSuccessfulResponse", mInstance.getToken());
Log.i("onSuccessfulResponse", mInstance.getmAuthorizationToken());
if (newLogin.getUser() != null) {
author.setText(newLogin.getUser().getNickname());
text.setText(newLogin.getUser().getUniversity());
}
}
@Override
public void onErrorResponse(int code, String error) {
Log.i("onErrorResponse", error);
}
});
mRest — это объект VolleyRestClient, который выполняет POST-запрос к этому адресу с типом, созданным Gson TypeToken (помните, что наше тело — это SuccessfulEntity).
Поскольку у нас наверняка будут данные Object, мы просто переопределим onSuccessfulResponse, приведем объект данных к тому же типу T SuccessfulEntity, который используется в TypeToken, и выполним нашу грязную работу.
Я не знаю, ясно ли я выразился, этот подход работает, если кому-то из вас нужны разъяснения, просто спросите :)
person
Dan.see
schedule
15.12.2015
Entity<T>
, который будет иметь все реквизиты изSuccessfulEntity<T>
иErrorEntity
... и сделать реквизиты, которые не распространены в этих классах, необязательными... и для проверки ошибок вы должны использоватьentity.getError() != null
- person Selvin   schedule 14.12.2015