在Android运行时切换Retrofit Base URL:简化开发环境与生产环境的切换
在Android开发中,Retrofit是一个由Square开发的类型安全的HTTP客户端库。它为API认证和网络请求提供了一个强大的框架。然而,在开发过程中,我们常常需要在不同的环境(如开发环境和生产环境)之间切换Base URL,这一操作在过去通常需要多个Retrofit实例,非常繁琐。本文将介绍一种通过使用Interceptor来在运行时动态切换Retrofit Base URL的简便方法。
引言
当我们使用Retrofit进行网络请求时,通常会在初始化时设置默认的Base URL:
return new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BuildConfig.PRODUCTION_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
虽然这种方式简单直接,但在需要切换Base URL时会变得复杂。为了避免维护多个Retrofit实例,我们可以使用Interceptor来动态更改Base URL。接下来,我们将详细介绍这种实现方法。
依赖配置
首先,在项目的build.gradle
文件中添加所需的依赖:
ext {
okHttpVersion ="4.8.1"
retrofitVersion ="2.9.0"
hiltVersion ="2.38.1"
}
dependencies{
// OkHttp
implementation "com.squareup.okhttp3:okhttp:$rootProject.okHttpVersion"
implementation "com.squareup.okhttp3:logging-interceptor:$rootProject.okHttpVersion"
// Retrofit2
implementation "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
implementation "com.squareup.retrofit2:converter-gson:$rootProject.retrofitVersion"
implementation "com.github.akarnokd:rxjava3-retrofit-adapter:3.0.0"
implementation "com.squareup.retrofit2:converter-protobuf:$rootProject.retrofitVersion"
// Hilt
implementation "com.google.dagger:hilt-android:$rootProject.hiltVersion"
annotationProcessor "com.google.dagger:hilt-android-compiler:$rootProject.hiltVersion"
annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0'
}
实现Shared Preferences管理器
为了管理当前环境的选择状态,我们需要创建一个Shared Preferences管理器(PreferenceHelper),用于读取和写入当前环境选择状态:
public classPreferenceHelper{
privateSharedPreferences sharedPreferences;
@Inject
publicPreferenceHelper(Context context){
sharedPreferences = context.getSharedPreferences("AppPrefs",Context.MODE_PRIVATE);
}
// 存储环境状态
publicvoidsetProdEnvironmentStatus(boolean status){
sharedPreferences.edit().putBoolean("isProd", status).apply();
}
// 获取环境状态
publicbooleanisProdEnvironment(){
return sharedPreferences.getBoolean("isProd",false);
}
}
创建HostSelectionInterceptor
接下来,我们创建一个Interceptor来处理环境切换的工作:
@Singleton
publicclassHostSelectionInterceptorimplementsInterceptor{
privatevolatileHttpUrlhost=HttpUrl.parse(BuildConfig.DEVELOPMENT_BASE_URL);
privatefinalPreferenceHelper preferenceHelper;
@Inject
publicHostSelectionInterceptor(PreferenceHelper preferenceHelper){
this.preferenceHelper = preferenceHelper;
setHostBaseUrl();
}
publicvoidsetHostBaseUrl(){
if(preferenceHelper.isProdEnvironment()){
this.host =HttpUrl.parse(BuildConfig.PRODUCTION_BASE_URL);
}else{
this.host =HttpUrl.parse(BuildConfig.DEVELOPMENT_BASE_URL);
}
}
@NotNull
@Override
public okhttp3.Responseintercept(Chain chain)throwsIOException{
Requestrequest= chain.request();
if(host !=null){
HttpUrl newUrl;
try{
newUrl = request.url().newBuilder()
.scheme(host.scheme())
.host(host.url().toURI().getHost())
.build();
}catch(URISyntaxException e){
thrownewIOException(e);
}
request = request.newBuilder().url(newUrl).build();
}
return chain.proceed(request);
}
}
配置Retrofit和OkHttpClient
然后,我们需要在提供Retrofit实例时注入HostSelectionInterceptor:
@Module
@InstallIn(SingletonComponent.class)
publicclassNetworkModule{
@Provides
@Singleton
publicRetrofitprovideRetrofitClient(ProtoConverterFactory protoConverterFactory, RxJava3CallAdapterFactory rxJava3CallAdapterFactory, OkHttpClient okHttpClient){
returnnewRetrofit.Builder()
.client(okHttpClient)
.baseUrl(BuildConfig.DEVELOPMENT_BASE_URL)// 默认Base URL
.addConverterFactory(protoConverterFactory)
.addCallAdapterFactory(rxJava3CallAdapterFactory)
.build();
}
@Provides
@Singleton
publicHostSelectionInterceptorprovideHostSelectionInterceptor(PreferenceHelper preferenceHelper){
returnnewHostSelectionInterceptor(preferenceHelper);
}
@Provides
@Singleton
publicOkHttpClientprovideOkHttpClient(@ApplicationContext Context context, HttpLoggingInterceptor httpLoggingInterceptor, HostSelectionInterceptor hostSelectionInterceptor){
longcacheSize=5*1024*1024;// 5 MB
Cachecache=newCache(context.getCacheDir(), cacheSize);
OkHttpClient.Builderbuilder=newOkHttpClient.Builder()
.cache(cache)
.retryOnConnectionFailure(true)
.connectTimeout(200,TimeUnit.SECONDS)
.readTimeout(200,TimeUnit.SECONDS)
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(hostSelectionInterceptor)
.followRedirects(true)
.followSslRedirects(true);
return builder.build();
}
}
在ViewModel中注入HostSelectionInterceptor
为了简化环境切换操作,我们可以在ViewModel或Activity中注入HostSelectionInterceptor:
@HiltViewModel
publicclassMainViewModelextendsViewModel{
privatefinalHostSelectionInterceptor hostSelectionInterceptor;
privatefinalPreferenceHelper preferenceHelper;
@Inject
publicMainViewModel(HostSelectionInterceptor hostSelectionInterceptor, PreferenceHelper preferenceHelper){
this.hostSelectionInterceptor = hostSelectionInterceptor;
this.preferenceHelper = preferenceHelper;
}
publicvoidswitchEnvironment(boolean isProd){
preferenceHelper.setProdEnvironmentStatus(isProd);
hostSelectionInterceptor.setHostBaseUrl();
}
}
使用Spinner切换环境
我们可以通过Spinner来切换开发环境和生产环境。以下是一个示例:
public classMainActivityextendsAppCompatActivity{
@Inject
HostSelectionInterceptor hostSelectionInterceptor;
@Inject
PreferenceHelper preferenceHelper;
privateMainViewModel mainViewModel;
@Override
protectedvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainViewModel =newViewModelProvider(this).get(MainViewModel.class);
setupHostSelectionSpinner();
}
privatevoidsetupHostSelectionSpinner(){
Spinnerspinner= findViewById(R.id.spinner_host_selection);
ArrayAdapter<String> adapter =newArrayAdapter<>(this, android.R.layout.simple_spinner_item,newString[]{"DEV","PROD"});
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(newAdapterView.OnItemSelectedListener(){
@Override
publicvoidonItemSelected(AdapterView<?> parent, View view, int position, long id){
if(position ==0){
mainViewModel.switchEnvironment(false);// 切换到开发环境
}else{
mainViewModel.switchEnvironment(true);// 切换到生产环境
}
}
@Override
publicvoidonNothingSelected(AdapterView<?> parent){}
});
}
}
总结
通过以上步骤,我们实现了在运行时动态切换Retrofit Base URL的功能。这种方法不仅简化了环境切换操作,还避免了维护多个Retrofit实例的繁琐工作。值得注意的是,这种环境切换主要适用于开发和调试阶段,因为所有请求都会经过这个Interceptor,可能会影响请求速度。
希望本文能为您在项目中实现动态切换Base URL提供帮助。如果有任何问题或建议,欢迎交流与讨论。