将绝对URL与Retrofit一起使用

时间:2015-01-23 18:28:42

标签: java android retrofit

我有HAL我正在使用的API,在很多情况下,我需要将请求(使用不同的方法)发送到我从API返回的网址。意思是我不想在我的改装api界面中硬编码URL的路径,但我想要的只是使用改造向该URL发送一个简单的请求。 我现在正在使用Volley而且我知道我可以将OkHttp用于此目的,但我想知道在Retrofit中是否有一种很好的方法可以做这样的事情?

4 个答案:

答案 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");

享受编码。

注意:Retrofit v1.4.0

上添加了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);
        }
    });

}

}