使用Retrofit v1.9.0添加重复参数

时间:2015-02-28 00:00:33

标签: android retrofit

有一个类似的问题here,但我的情况有点不同。

我正在尝试提出类似以下的请求:

http://www.example.com/abc?foo=def&foo=ghi&foo=jkl&bar=xyz

我有两个问题让事情变得困难。首先,重复的参数(多次设置“foo”)阻止了QueryMap的使用(我没有选择以不同的方式传递查询字符串中的值,就像数组一样)。其次,我正在使用的查询参数是动态的,所以我不能真正使用Query并为它提供给定参数名称的值列表,因为我不知道参数名称,直到我提出要求。

我尝试升级的代码是使用较旧版本的Retrofit,但不知何故,它有一个QueryList的概念,它使List NameValuePairretrofit.http.QueryList通过在查询参数中作为名称(及其值作为值)并允许重复参数。我没有在Retrofit的源代码历史记录或网络上看到{{1}}的任何引用,所以我不确定这是否是当时的自定义添加。在任何情况下,我都试图找到在最新版本中复制该功能的最佳方式,所以任何帮助都将不胜感激!

3 个答案:

答案 0 :(得分:17)

为了跟进,我能够通过使用QueryMap和一些黑客来解决这个问题。基本上我将List NameValuePair转换为HashMap,我检查是否已经有密钥,如果我这样做,我将相同密钥的新值附加到旧值。所以基本上(键,值)会变成(键,值和键=值2)。这样,当构造查询字符串时,我将根据需要使用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解决方案。希望这可以帮助遇到同样问题的其他任何人!

答案 1 :(得分:1)

接口:

@GET()
Call<List<CustomDto>> getCustomData(@Url String url);

请求数据:

 String params = "custom?";
 for (Integer id : ids) {
      params += "id=" + id.toString() + "&";
 }
 params = params.substring(0, params.length() - 1);
 api.getCustomData(params).enqueue(callback);

答案 2 :(得分:-1)

只需将列表传递给@Query:

@GET("/api")
Response shareItem(@Query("email")List<String> email);