После долгой битвы с дженериками и стиранием стилей я, наконец, сделал это.
Итак, я публикую это для тех, кто имеет такую же проблему, как я, и нуждается в решении, не волнуясь.
Мои 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 для списка данных объектов, onErrorResponse для 4XX/Ошибки 5XX;
- Наш объект/список данных будет анализироваться на более универсальный тип (список и объект), а затем передан нашему пользовательскому ресепозитору ListenerListener.
Полный пример такого подхода:
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).
Поскольку у нас будет объект данных, конечно, мы будем просто переопределить onSuccessfulResponse, литая объект данных к тому же типа Т SuccessfulEntity, используемого в TypeToken, и сделать нашу грязную работу.
Я не знаю, был ли я ясно, этот подход работает, если некоторые из вас нуждается в некотором уточнении, просто спросить :)
почему не '' Entity который будет иметь все реквизиты из '' SuccessfulEntity и 'ErrorEntity' ... и создавать реквизиты, которые не являются обычными в этих классах, необязательно ... и для проверки ошибок вы должны использовать' entity.getError()! = Null' –
Selvin
@Selvin и как мне получить класс> пройти к пользовательскому запросу для разбора GSON? –
так же, как вы хотите сделать с SuccessfulEntity ... так что вы должны знать тип T перед созданием пользовательского запроса –
Selvin