How to Change API Base Url at Runtime(Retrofit,Android,Java)?

jes*_*aul 5 java rest android retrofit2

I need to change base url at run time. I have login button and when login button click time i am called my login api like below :

login api = http://192.168.0.61/api/authenticate

API_BASE_URL = http://192.168.0.61/api/

when i get success response from first api i get client server url for changing baseUrl.

CompanyUrlConfigEntity companyUrlConfigEntity = response.body(); like below :

String clientUrl = companyUrlConfigEntity. getBaseUrl();

                            clientUrl = http://192.168.0.238/api/
Run Code Online (Sandbox Code Playgroud)

In this project mainly for client or company based.So they have their own server. Each company has using more than 20 api's. So i need to change base url .

I am also checked below link for changing base url:

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

and changed code like that

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()));
}
Run Code Online (Sandbox Code Playgroud)

when i debugged and checked my baseUrl then it shows properly like below:

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.
Run Code Online (Sandbox Code Playgroud)

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);
}
}
Run Code Online (Sandbox Code Playgroud)

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) {

        }
    });
}
Run Code Online (Sandbox Code Playgroud)

小智 3

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

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

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

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

public ApiClient getApiClient() {
    apiClient =  ServiceGenerator.createService(ApiClient.class);
    return apiClient;
}
Run Code Online (Sandbox Code Playgroud)

看看这样是否效果更好。

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

ServiceGenerator.changeApiBaseUrl(baseUrls);
dataProcessController.regenerateClient();
Run Code Online (Sandbox Code Playgroud)

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