为了跟进,我能够通过使用 QueryMap 和一些 hack 来解决这个问题。基本上,我将 NameValuePairs 的 List 转换为 HashMap,在其中检查我是否已经拥有密钥,如果有,则将同一密钥的新值附加到旧值。所以本质上 (key, value) 会变成 (key, value&key=value2)。这样,在构造查询字符串时,我将根据需要拥有 key=value&key=value2。为了让它工作,我需要自己处理值编码,这样我在值中包含的其他 & 和等号就不会被编码。
所以HashMap 是从List 构造的,如下所示:
public static HashMap<String, String> getPathMap(List<NameValuePair> params) {
HashMap<String, String> paramMap = new HashMap<>();
String paramValue;
for (NameValuePair paramPair : params) {
if (!TextUtils.isEmpty(paramPair.getName())) {
try {
if (paramMap.containsKey(paramPair.getName())) {
// Add the duplicate key and new value onto the previous value
// so (key, value) will now look like (key, value&key=value2)
// which is a hack to work with Retrofit's QueryMap
paramValue = paramMap.get(paramPair.getName());
paramValue += "&" + paramPair.getName() + "=" + URLEncoder.encode(String.valueOf(paramPair.getValue()), "UTF-8");
} else {
// This is the first value, so directly map it
paramValue = URLEncoder.encode(String.valueOf(paramPair.getValue()), "UTF-8");
}
paramMap.put(paramPair.getName(), paramValue);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
return paramMap;
}
那么我的请求是这样的:
@GET("/api/")
List<Repo> listRepos(@QueryMap(encodeValues=false) Map<String, String> params);
我的服务调用如下所示:
// Get the list of params for the service call
ArrayList<NameValuePair> paramList = getParams();
// Convert the list into a map and make the call with it
Map<String, String> params = getPathMap(paramList);
List<Repo> repos = service.listRepos(params);
我最初尝试使用Path 的解决方案,我尝试手动构造查询字符串,但查询字符串中不允许替换块,所以我使用了这个 QueryMap 解决方案。希望这可以帮助遇到同样问题的其他人!