我有HAL我正在使用的API,在很多情况下,我需要将请求(使用不同的方法)发送到我从API返回的网址。意思是我不想在我的改装api界面中硬编码URL的路径,但我想要的只是使用改造向该URL发送一个简单的请求。 我现在正在使用Volley而且我知道我可以将OkHttp用于此目的,但我想知道在Retrofit中是否有一种很好的方法可以做这样的事情?
答案 0 :(得分:23)
最近Square已发布Retrofit v2.0.0 BETA,它内置了对动态网址的支持。即使图书馆处于测试阶段,基于Jake Wharton在DroidCon NYC 2015中告诉我们的内容,所有api都是稳定的,不会改变。我个人将它添加到我的作品中,所以由你决定。
如果您决定进行升级,您会发现以下链接很有用:
Jake Wharton presentation @ DroidCon NYC 2015
A very good guide on the changes
简单来说,您现在可以在没有任何路径的情况下使用api注释(如@GET或@POST等),然后将@URL传递给该方法将用于调用的api方法。
---------------- Retrofit 1.x
我想出了一个很好的方法,并希望分享它。
诀窍是在创建RestAdapter时使用动态URL作为终点,然后在API接口上使用空路径。
我是这样做的:
public RestAdapter getHostAdapter(String baseHost){
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(baseHost)
.setRequestInterceptor(requestInterceptor)
.build();
return restAdapter;
}
我使用这种方法构建我的restAdapter,然后在我的界面中显示:(如果您的URL添加了查询参数,这将无效。请参阅下一个答案以获得该案例的解决方案) 强>
public interface General {
@GET("/")
void getSomething(Callback<SomeObject> callback);
}
最后像这样使用它们:
getHostAdapter("YOUR_DYNAMIC_URL").create(General.class)
.getSomething(new Callback<SomeObject>(){
...
})
希望它有所帮助。
答案 1 :(得分:3)
如果您的网址上有查询参数,则上述解决方案无效,因为它会添加&#39; /&#39;在基本网址的末尾。例如,如果您的网址是
https://www.google.com/?q=test
然后上述解决方案将尝试将请求发送到
https://www.google.com/?q=test/
因商城格式而失败。
我们可以做的是一个额外的步骤并解析网址。解析我的意思是只取出所有网址参数并在QueryMap
中发送。
我们应该拥有与上述相同的结构,并对我们的界面进行一些改动
public interface General {
@GET("/")
void getSomething(@QueryMap Map<String,String> queryMap, Callback<SomeObject> callback);
}
我刚刚在上面的界面添加了QueryMap
,现在我们可以使用这个解析器方法了:
public static void getSomething(@NonNull String urlString, @NonNull Callback<SomeObject> callback){
Uri uri = Uri.parse(urlString);
Set<String> queryParameterNames = uri.getQueryParameterNames();
String host = uri.getHost();
HashMap<String,String> queryMap = new HashMap<>();
Iterator<String> iterator = queryParameterNames.iterator();
while(iterator.hasNext()){
String queryName = iterator.next();
String queryParameter = uri.getQueryParameter(queryName);
queryMap.put(queryName, queryParameter);
}
getHostAdapter(host)
.create(General.class)
.getSomething(queryMap, callback);
}
现在您可以像这样调用此方法:
getSomething("https://www.google.com/?q=test");
享受编码。
上添加了QueryMap
答案 2 :(得分:3)
我的网址上还需要一个路径,所以我这样做了:
@GET("/{path}")
void getMatcherUrl(@Path(value = "path", encode = false) String path, @QueryMap Map<String, String> queryMap, RestCallback<MatcherResponse> matcherResponse);
/**
* Need to create a custom method because i need to pass a absolute url to the retrofit client
*
* @param urlString
* @param matcherResponse
*/
public void getMatcherUrl(@NonNull String urlString, @NonNull RestCallback<MatcherResponse> matcherResponse) {
Uri uri = Uri.parse(urlString);
Set<String> queryParameterNames = uri.getQueryParameterNames();
String host = uri.getHost();
String path = (uri.getPath().startsWith("/")) ? uri.getPath().substring(1) : uri.getPath();
HashMap<String, String> queryMap = new HashMap<>();
Iterator<String> iterator = queryParameterNames.iterator();
while (iterator.hasNext()) {
String queryName = iterator.next();
String queryParameter = uri.getQueryParameter(queryName);
queryMap.put(queryName, queryParameter);
}
getApiCoreService(host)
.getMatcherUrl(path, queryMap, matcherResponse);
}
public ApiCoreService getApiCoreService(String host) {
if (StringUtils.isEmpty(host))
this.endpoint = new RestEndpoint(RemoteConfigurationManager.getInstance().getApiCore(), "ApiCore");
else
this.endpoint = new RestEndpoint(host, "ApiCore");
return apiCoreService;
}
答案 3 :(得分:1)
添加以上两个答案,这是一个使用Queryparam并触发绝对URL的工作类
public class VideoClient {
private static final String TAG = "VideoCLient";
private final RestAdapter restAdapter;
private General apiService;
private String hostName;
private LinkedHashMap<String, String> queryMap;
private String Url_Path;
public VideoClient(String BASE_URL) {
Log.d(TAG,"Base url is "+BASE_URL);
hostName =getHostNameAndGenerateQueryMap(BASE_URL);
Gson gson = new GsonBuilder()
.create();
RequestInterceptor interceptor = new RequestInterceptor() {
@Override
public void intercept(RequestFacade request) {
}
};
restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint("http://"+hostName)
.setClient(new OkClient())
.setConverter(new GsonConverter(gson))
.setRequestInterceptor(interceptor)
.build();
}
private String getHostNameAndGenerateQueryMap(String urlString) {
Uri uri = Uri.parse(urlString);
Url_Path = (uri.getPath().startsWith("/")) ? uri.getPath().substring(1) : uri.getPath();
Set<String> queryParameterNames = uri.getQueryParameterNames();
String host = uri.getHost();
queryMap = new LinkedHashMap<>();
Iterator<String> iterator = queryParameterNames.iterator();
while (iterator.hasNext()) {
String queryName = iterator.next();
String queryParameter = uri.getQueryParameter(queryName);
Log.d(TAG,"query name "+queryName +" query param "+queryParameter);
queryMap.put(queryName, queryParameter);
}
return host;
}
public interface General {
/*void getVideo(@Path("auth_token") String authId,
@Query("et") String systemTime,@Query("service_id") String serviceID,
@Query("protocol") String scheme,@Query("play_url") String url,
@Query("us") String us,Callback<String> callback);
*/
@GET("/{path}")
getVideo(@Path(value="path", encode=false)String path,@QueryMap LinkedHashMap<String, String> queryMap);
}
public void getVideoDetails() {
Log.i("firing", "getVideoApi");
Log.d(TAG, "firing " + Url_Path + " function");
restAdapter.create(General.class).getVideo(Url_Path,queryMap, new Callback<Object>() {
@Override
public void success( Object o, Response response) {
Log.d(TAG," Success Response is "+response );
}
@Override
public void failure(RetrofitError error) {
Log.d(TAG, "Failure " + "Internal Error" + error);
}
});
}
}