如何在运行时更改API基础URL(Retrofit,Android,Java)?

5
我需要在运行时更改基础 URL。 我有登录按钮,当点击登录按钮时,我会调用我的登录 API,如下所示:
登录 API = http://192.168.0.61/api/authenticate API_BASE_URL = http://192.168.0.61/api/ 当我从第一个 API 中获得成功响应时,我会获取客户端服务器 URL 以更改 baseUrl。
CompanyUrlConfigEntity 公司URL配置实体 = response.body();
如下所示:
String clientUrl = companyUrlConfigEntity.getBaseUrl();
                            clientUrl = http://192.168.0.238/api/

在这个项目中,主要是为客户或公司提供服务,因此他们有自己的服务器。每个公司都使用 20 多个 API。所以我需要改变基本 URL。
我还查看了下面的链接以更改基本 URL:

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类。请查看一下。 - jesto paul
@Macmist,你好,我刚刚更新了我的问题,添加了changeApiBaseUrl()调用函数和新的api函数调用,已更改baseUrl(LoginFragment.java)。请查看一下。等待您的回复。 - jesto paul
也许你需要两个Retrofit客户端? - Raj
@Macmist,感谢您的回复。ApiClient没有重新生成。

ApiClient.java

public interface ApiClient {@POST("authenticate") Call<Void> login(@Body Login login); } }

DataProcessController.java

public class DataProcessController {private ApiClient apiClient = null; private DataProcessController() { apiClient = ServiceGenerator.createService(ApiClient.class);} }
- jesto paul

以下是BaseFragment的代码:

public abstract class BaseFragment extends Fragment {protected DataProcessController dataProcessController = DataProcessController .getDataProcessController();}
- jesto paul
显示剩余3条评论
2个回答

3
根据您的评论,我认为您正确地在构建器上更改了API URL,但是您的第二个调用仍然使用了一个服务实例,其中URL没有更改。
更详细地解释一下,根据我的理解,这是整个执行过程:
- 当片段创建时,apiClient被创建并指向第一个url。 - 在您的第一个调用中,使用dataProcessController.getApiClient()获取指向第一个url的服务,然后执行调用。 - 当调用成功时,从结果中读取新的url,并使用该新url更新ServiceGenerator。然后执行logins()方法。 - 在该方法中,重新调用dataProcessController.getApiClient()并使用它进行第二次调用。但是,由于您从未重新执行过apiClient = ServiceGenerator.createService(ApiClient.class),所以您获取的apiClient实例仍然指向第一个url,因为它没有被通知url已更改。
在这里我会尝试的是更改DataProcessController类中的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);
    }
}

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

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

每次执行dataProcessController.getApiClient()时,您应该得到一个指向正确URL的客户端。


1
谢谢,兄弟,它正在运行。 ServiceGenerator.changeApiBaseUrl(baseUrls); dataProcessController.regenerateClient(); 对我有用。 - jesto paul

-2

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

你应该遵循 Firebase 远程配置的概念。在这里,你不需要将基本 URL 存储在源代码中,它将从存储在 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
                }
            }
        });

由于回答与提问者的问题无关,因此被踩了。这不是关于 Firebase 的问题,而是关于 Retrofit 的问题。 - Fer B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接