【问题标题】:How to Change API Base Url at Runtime(Retrofit,Android,Java)?如何在运行时更改 API Base Url(Retrofit、Android、Java)?
【发布时间】:2018-10-30 07:15:16
【问题描述】:

我需要在运行时更改基本网址。 我有登录按钮,当登录按钮单击时,我被称为登录 api 如下:

登录 api = http://192.168.0.61/api/authenticate

API_BASE_URL = http://192.168.0.61/api/

当我从第一个 api 获得成功响应时,我会获得用于更改 baseUrl 的客户端服务器 url。

CompanyUrlConfigEntity companyUrlConfigEntity = response.body(); 如下所示:

字符串 clientUrl = companyUrlConfigEntity。 getBaseUrl();

                            clientUrl = http://192.168.0.238/api/

在这个项目中主要是针对客户或公司的。所以他们有自己的服务器。 每家公司都使用了 20 多个 api。 所以我需要更改基本网址。

我还检查了下面的链接以更改基本网址:

https://futurestud.io/tutorials/retrofit-2-how-to-change-api-base-url-at-runtime-2

并像这样更改代码

public static void changeApiBaseUrl(String newApiBaseUrl) {
    API_BASE_URL = newApiBaseUrl;

    builder = new Retrofit.Builder()
            .baseUrl(API_BASE_URL)
                    .addConverterFactory(new NullOnEmptyConverterFactory())
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(new Gson()));
}

当我调试并检查了我的 baseUrl 时,它会正确显示如下:

API_BASE_URL =  http://192.168.0.238/api/



But when i call my customer api it shows the my first base url calling,
the url not changed.

expected customer api : http://192.168.0.238/api/customers
reality customer api : http://192.168.0.61/api/customers


I am also checked below link :

https://futurestud.io/tutorials/retrofit-2-how-to-use-dynamic-urls-for-requests

thats working , But each api need to pass fullPath url with each api like below:
@GET
public Call<ResponseBody> profilePicture(@Url String url);

But using this method , each api calling place i need to attach full path of url.

There is any other options? Please help me.

ServiceGenerator.class

    public class ServiceGenerator {

  public static String API_BASE_URL = "http://192.168.0.61/api/";

   private static Retrofit retrofit;

 private static OkHttpClient.Builder httpClient = new 
 OkHttpClient.Builder();

private static Retrofit.Builder builder =
        new Retrofit.Builder()
                .baseUrl(API_BASE_URL)
                .addConverterFactory(new NullOnEmptyConverterFactory())
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(new 
       Gson()));

   private ServiceGenerator() {

   }

 public static void changeApiBaseUrl(String newApiBaseUrl) {
         API_BASE_URL = newApiBaseUrl;

       builder = new Retrofit.Builder()
            .baseUrl(API_BASE_URL)
                    .addConverterFactory(new NullOnEmptyConverterFactory())
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create(new Gson()));


}   

 public static Retrofit retrofit() {
    return retrofit;
}
public static <S> S createService(Class<S> serviceClass) {
    return createService(serviceClass, null, null);
}

  public static <S> S createService(Class<S> serviceClass,
                                  final String authToken,
                                  final ProgressListener progressListener) {
    if (authToken != null) {
           httpClient.addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request original = chain.request();

                final String headerValue = AUTHORIZATION_TYPE + authToken;
                Request request = original.newBuilder()
                        .header(AUTHORIZATION_HEADER_KEY, headerValue)
                        .method(original.method(), original.body())
                        .build();
                return chain.proceed(request);
            }
        });
    }

    addResponseProgressListener(progressListener);

    if (BuildConfig.DEBUG) {
        HttpLoggingInterceptor httpLoggingInterceptor = new 
        HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        httpClient.addInterceptor(httpLoggingInterceptor);
    }


    if (authToken != null) {
        if (picasso == null) {
            setUpPicasso(authToken);
        }
    }


    OkHttpClient client = httpClient.build();
    httpClient.connectTimeout(15, TimeUnit.SECONDS);
    httpClient.readTimeout(2, TimeUnit.MINUTES);
    httpClient.writeTimeout(2, TimeUnit.MINUTES);
    retrofit = builder.client(client).build();

    return retrofit.create(serviceClass);
}
}

LoginFragment.java

@OnClick(R.id.bt_login)
void onLogin() {

    checkValidityOfUser();

}

private void checkValidityOfUser() {
    final Login login = getLoginCredentials();

    Call<CompanyUrlConfigEntity> callCheckValidity = dataProcessController.
            getApiClient().
            checkValidityOfUsers(login.getUsername());

    callCheckValidity.enqueue(new Callback<CompanyUrlConfigEntity>() {
        @Override
        public void onResponse(Call<CompanyUrlConfigEntity> call,
                               Response<CompanyUrlConfigEntity> response) {


            if (response.code() == 200) {

                CompanyUrlConfigEntity companyUrlConfigEntity = response.body();

                boolean status = companyUrlConfigEntity.isValidUser();

                if (status) {

                    String baseUrls = companyUrlConfigEntity.
                            getBaseUrl();
                    baseUrls = baseUrls + "/api/";
                    ServiceGenerator.changeApiBaseUrl(baseUrls);
                    logins();
                } else {

                    ToastHelper.show("please contact  admin");

                }


            } else {

                ToastHelper.show("" + response.code() + response.message());

            }

        }

        @Override
        public void onFailure(Call<CompanyUrlConfigEntity> call, Throwable t) {

            ToastHelper.show("please contact  admin");
        }
    });
}


private void logins() {
    login = getLoginCredentials();
    Call<Void> callLogin = dataProcessController.
            getApiClient().
            login(login);

    callLogin.enqueue(new Callback<Void>() {
        @Override
        public void onResponse(Call<Void> call, Response<Void> response) {

            if (response.code() == 200) {

            } else if (response.code() == 401) {

            }
        }

        @Override
        public void onFailure(Call<Void> call, Throwable t) {

        }
    });
}

【问题讨论】:

  • 也许您已经实现了单例模式并获取了旧的构建器对象。请在获取构建器对象的位置显示更多代码
  • @ZaidMirza ,我通过添加我的 ServiceGenerator 类更新了我的问题。请查看它。
  • 什么时候调用 changeApiBaseUrl 方法?您何时使用更改后的 API 进行调用?
  • @Macmist,嗨,我刚刚更新了我的问题,添加了 changeApiBaseUrl() 调用函数和新的 api 函数调用,更改了 baseUrl(LoginFragment.java)。请查看它。等待您的回复。
  • 也许您需要两个改造客户?

标签: java android rest retrofit2


【解决方案1】:

根据您的 cmets,我会说您正确更改了构建器上的 API url,但您的第二次调用仍使用 url 未更改的服务实例。

再解释一下,据我了解,这就是一切的执行方式:

  • 创建fragment时,会创建apiClient并指向第一个url
  • 在您的第一次调用中使用dataProcessController.getApiClient(),您将获得指向第一个 url 的服务,然后执行调用。
  • 当调用成功时,您从结果中读取新的 url 并使用该新 url 更新 ServiceGenerator。然后执行logins() 方法。
  • 在该方法中,您调用dataProcessController.getApiClient() 并使用它进行第二次调用。但是,由于您从未重做 apiClient = ServiceGenerator.createService(ApiClient.class);,因此您获得的 apiClient 实例仍然指向第一个 url,因为它没有被通知该 url 已更改。

我想在这里尝试的是,将 getApiClient() 类中的 getApiClient() 方法更改为如下所示:

public ApiClient getApiClient() {
    apiClient =  ServiceGenerator.createService(ApiClient.class);
    return apiClient;
}

看看这是否更好。

或者,如果您不想在该函数中重新生成服务,您也可以执行以下操作:

public class DataProcessController { 
    private ApiClient apiClient = null; 

    private DataProcessController() { 
        regenerateClient(); 
    }

    public ApiClient getApiClient() { return apiClient; }

    // add this to regenerate the client whenever url changes
    public void regenerateClient() {
        apiClient = ServiceGenerator.createService(ApiClient.class);
    }
}

然后,每次更改网址时,请执行以下操作:

ServiceGenerator.changeApiBaseUrl(baseUrls);
dataProcessController.regenerateClient();

你应该得到一个客户端,每次你做dataProcessController.getApiClient()时都指向正确的url

【讨论】:

  • 感谢它的工作。 ServiceGenerator.changeApiBaseUrl(baseUrls); dataProcessController.regenerateClient();它对我有用。
【解决方案2】:

https://segunfamisa.com/posts/firebase-remote-config

您应该遵循 firebase 远程配置的概念。在这里,您不需要将基本 Url 存储在源代码中,它将从存储在 firebase 服务器上的 firebase 配置值中检索。

// fetch
mRemoteConfig.fetch(3000)
        .addOnCompleteListener(this, new OnCompleteListener<Void>() {
            @Override
            public void onComplete(Task<Void> task) {
                if (task.isSuccessful()) {
                    // update your base url here. 
                } else {
                    //task failed
                }
            }
        });

【讨论】:

  • 投反对票,因为这与 OP 问题无关。这根本不是关于 Firebase,而是关于改造。
猜你喜欢
  • 1970-01-01
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
  • 2016-05-31
  • 1970-01-01
  • 2020-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多