经过与泛型和类型擦除的长期斗争,我终于做到了。
所以我把这篇文章发给和我一样有同样问题并且需要解决方案的人。
我的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());
}
}
};
}
}
这取决于我的需要,但我会解释一般概念。
所以我有一个自定义请求,如我的问题中所述,我想将其解析为正确的数据类型。
更具体地说,我只能在 GET 请求(分页元素等)上拥有 JSONArray 数据,因此我需要找到一种方法来区分这两种情况(当然,我知道在哪些情况下我'会得到一个列表或一个对象)。
我们不能简单地在泛型类中使用其类型从 Json 创建 POJO(因为 Java 类型擦除),所以我们需要对象类型 预先。
但我们能做的是:
-
在我们的自定义请求中,在 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 从 RepositoryListener 构造一个 Response.Listener,它有 3 个方法可以覆盖:onSuccessfulResponse 用于对象数据,onSuccessfulResponse2 用于对象数据列表,onErrorResponse 用于 4XX/5XX 错误;
- 我们的数据对象/列表将被解析为更多的泛型类型(列表和对象),然后传递给我们的自定义侦听器 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 对象,它使用由 Gson TypeToken 构造的 Type 向该地址执行 POST 请求(请记住,我们的主体是一个成功实体)。
由于我们肯定会有一个 Object 数据,我们只需覆盖 onSuccessfulResponse,将数据对象转换为 TypeToken 中使用的 SuccessEntity 的相同类型 T,然后完成我们的繁琐工作。 p>
我不知道我是否清楚,这种方法有效,如果你们中的一些人需要澄清,请问:)