Singleton for Retrofit and Network Request Optimization
I. Background
Background: Currently, most requests in the project are made using Retrofit by declaring interfaces to request the network. However, there are issues with this approach, such as creating a new interface instance for each network request, which unnecessarily consumes resources. Additionally, old business logic that uses HttpClient for network requests poses a risk of memory leaks due to listeners being held, and the internal encapsulation of RxJava operators fails to fully leverage the advantages of RxJava. Many requests do not use Gson for automatic serialization of objects but declare a JsonObject object as the return type and then serialize it in the main thread.
II. Implementation
2.1 Retrofit Singleton Implementation
RetrofitService singleton caching implementation:
Unified method to get Retrofit singleton:
It allows the interface to define its own Retrofit instance and declares annotations in the corresponding Service interface.
@Provider(ServiceGenerator.MapRetrofitProvider.class)
public interface OrangeDotServiceApi {
// Request for the orange dot
@GET("xxxx")
Observable<Response<ResultX<SuggestLocInfo>>> getOrangeDot(@QueryMap HashMap<String, Object> params);
}
Implementation class for a custom Retrofit instance:
public class ServiceGenerator {
public static class MapRetrofitProvider implements RetrofitProvider {
@Override
public Retrofit createRetrofit(Retrofit.Builder builder) {
String baseUrl = ApiUtils.getMeta2(Utils.getContext()).getLbs_rgeo_url();
if (TextUtils.isEmpty(baseUrl)) {
baseUrl = https://github.com/MicroKibaco;
}
return builder.client(OkHttpClientManager.getOkhttpClient()).baseUrl(baseUrl).build();
}
}
}
Using RetrofitManager to make requests:
领英推荐
private void requestByMapAPi(SuggestRequest suggestRequest, Stop stop, LifecycleOwner lifecycleOwner) {
RetrofitManager.get(OrangeDotServiceApi.class)
.getOrangeDot(getRequestParamsMap(suggestRequest))
.compose(RxjavaUtils.commonTransform())
.as(AutoDisposeUtils.bindToLifecycle(lifecycleOwner))
.subscribe(new Observer<Response<ResultX<SuggestLocInfo>>>() {
// ...
});
}
RetrofitManager Implementation:
public class RetrofitManager {
private static final Map<Class<?>, Object> sInstanceMap = new ConcurrentHashMap<>();
@SuppressWarnings("unchecked")
public static <T> T get(Class<T> service) {
if (service == null) {
return null;
}
Object instance = sInstanceMap.get(service);
if (instance == null) {
Retrofit retrofit;
Provider provider = service.getAnnotation(Provider.class);
if (provider != null) {
try {
retrofit = provider.value().newInstance().createRetrofit(DefaultRetrofitProvider.getInternalRetrofitBuilder());
} catch (IllegalAccessException | InstantiationException e) {
throw new RuntimeException("RetrofitProvider: " + provider.value().getSimpleName() + " creation failed");
}
} else {
retrofit = DefaultRetrofitProvider.getDefaultRetrofit();
}
sInstanceMap.put(service, instance = retrofit.create(service));
}
return (T) instance;
}
public static void destroy(Class<?> cls) {
sInstanceMap.remove(cls);
}
public static void reset() {
sInstanceMap.clear();
}
}
DefaultRetrofitProvider Implementation:
public class DefaultRetrofitProvider implements RetrofitProvider {
private static Retrofit SIMPLE_RETROFIT;
@Override
public Retrofit createRetrofit(Retrofit.Builder builder) {
return getDefaultRetrofit();
}
public static Retrofit getDefaultRetrofit() {
if (SIMPLE_RETROFIT == null) {
String baseUrl = ApiUtils.getMeta2(Utils.getContext()).getApiUrlPrefix2();
if (TextUtils.isEmpty(baseUrl)) {
baseUrl = https://github.com/MicroKibaco;
}
SIMPLE_RETROFIT = BUILDER.client(OkHttpClientManager.getOkhttpClient()).baseUrl(baseUrl).build();
}
return SIMPLE_RETROFIT;
}
public static Retrofit.Builder getInternalRetrofitBuilder() {
return BUILDER;
}
private static final Retrofit.Builder BUILDER = new Retrofit.Builder()
.addConverterFactory(StringConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(GsonUtil.getCollectionGson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
}
2.2 Refactoring Old Network Requests
Example of refactoring HttpClient network requests:
java// Before refactoring
private void getHotfix() {
new HttpClient.Builder()
.baseUrl(ApiUtils.getMeta2(this).getApiUrlPrefix2())
.listener(new OnHttpResultListener<JsonObject>() {
@Override
public void onSuccess(JsonObject jsonObject) {
// ...
}
@Override
public void onError(Throwable throwable) {
}
})
.build()
.request(new BaseApi<JsonObject>() {
@Override
public Observable<JsonObject> getObservable(Retrofit retrofit) {
return retrofit.create(MainApiServcie.class).vanGetHfdata(map);
}
});
}
// After refactoring
private void getHotfix() {
RetrofitManager.get(MainApiServcie.class)
.vanGetHfdata(map)
.compose(RxjavaUtils.commonTransform())
.as(AutoDisposeUtils.bindToLifecycle(this))
.subscribe(new SingleObserver<JsonObject>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onSuccess(@NonNull JsonObject jsonObject) {
// ...
}
@Override
public void onError(@NonNull Throwable e) {
}
});
}
Refactoring ServiceGenerator custom RetrofitService network requests:
// Before refactoring
public class ServiceGenerator {
public static <S> S createService(Class<S> serviceClass) {
String baseUrl = ApiUtils.getMeta2(Utils.getContext()).getApiUrlPrefix2();
if (TextUtils.isEmpty(baseUrl)) {
baseUrl = https://github.com/MicroKibaco;
}
Retrofit retrofit = builder.baseUrl(baseUrl)
.client(OkHttpClientManager.getOkhttpClient())
.build();
return retrofit.create(serviceClass);
}
}
private void getOrder() {
ServiceGenerator.createService(FreightApiService.class)
.orderRepeat(param)
.compose(RxjavaUtils.commonTransform())
.compose(RxProgress.bindToLifecycle(activity))
.as(AutoDisposeUtils.bindToLifecycle(activity.getLifecycle()))
.subscribe();
}
// After refactoring
private void getOrder() {
RetrofitManager.get(FreightApiService.class)
.orderRepeat(param)
.compose(RxjavaUtils.commonTransform())
.compose(RxProgress.bindToLifecycle(activity))
.as(AutoDisposeUtils.bindToLifecycle(activity.getLifecycle()))
.subscribe();
}
III. Summary
Summary of the code and experience accumulated from this technical application: