将Retrofit服务声明分成多个接口
Divide Retrofit service declaration into multiple interfaces
我正在创建一个链接到 API 的应用程序,其中包含大约 265 种方法。我非常想将这些 API 的声明分解成多个文件,以保持它们的组织性和可访问性。但是 Retrofit 明确禁止通过扩展组合接口。
java.lang.IllegalArgumentException: Interface definitions must not extend other interfaces.
我一直在尝试声明如下。
public interface ApiService extends ProfileService, AccountService {
// Empty interface, methods divided into other services
}
public interface ProfileService {
@GET("/api/v1/protected/profile")
public void getProfile(Callback<Profile> callback);
...
}
public interface AccountService {
@GET("/api/v1/protected/account")
public void getAccount(Callback<Account> callback);
...
}
在拉取请求中有关于此问题的讨论。库作者已经决定像这样扩展接口不符合库的精神。
https://github.com/square/retrofit/pull/676
Jake Wharton(作者)说 "Retrofit favors composition." 并回应 "Do you really have a single adapter with a ton of proxies?","Yes. They are generated from a service declaration in protos. One interface per service."
我一直在阅读有关组合与继承的内容,但未能掌握如何实现分解声明的目标。
如何划分接口声明?是否有我遗漏的最佳实践?
谢谢。
只需创建单独的接口。
public interface ProfileService {
/* ... */
}
public interface AccountService {
/* ... */
}
ProfileService profileService = mRestAdapter.create(ProfileService.class);
AccountService accountService = mRestAdapter.create(AccountService.class);
我仍在试验这是否是使用它的最佳方式,但这是我目前所拥有的。它可能不是最干净的方法,但我喜欢它而不是一个有 100 api 个调用的服务。稍微拆分一下,使其更易于阅读。
这是访问数据的主要class。我已经看到很多将我拥有的两个静态方法分开成一个单独的 class 但我只是将它作为一个包含在内。
public class RetrofitApi {
public enum ApiTypes {
USER_API(UserApi.class);
private final Class<? extends RetrofitApi> apiClass;
ApiTypes(Class<? extends RetrofitApi> apiClass){
this.apiClass = apiClass;
}
Class<? extends RetrofitApi> getApiType() {return this.apiClass;}
}
public static <T> T getApi(RetrofitApi.ApiTypes type) {
try {
return (T) type.getApiType().newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static RestAdapter getRestAdapter() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.setLogLevel(retrofit.RestAdapter.LogLevel.HEADERS)
.build();
return restAdapter;
}
}
每项服务都有自己的 api。这确实意味着更多 classes。我将它们拆分为 api、服务、模型。 API 是您将使用和公开的高级别。服务或多或少只是一个电话列表。而Model就是模型(数据对象)。
public class UserApi extends RetrofitApi {
private UserService service;
public UserApi() {
RestAdapter restAdapter =
RetrofitApi.getRestAdapter();
service = restAdapter.create(UserService.class);
}
public void login(String email,
String password,
Callback<User> callback) {
service.login(email, password, callback);
}
}
服务就是接口。它或多或少只是暴露的 api 个调用列表。
public interface UserService {
@GET("/api/users/login")
void login(@Query("email") String email,
@Query("password") String password,
Callback<User> callback);
}
然后使用它。
UserApi api = RetrofitApi.getApi(RetrofitApi.ApiTypes.USER_API);
api.login(email,password,callback);
这是项目结构。对我来说,目前看起来很干净。我相信当我有 20 多个时,它最终会变大。但是当这 20 个有多个调用时,它可能会更干净一些。
您可以尝试以下方法。
创建2接口class.
- ARetrofitApi
- BRetrofitApi
拨打电话
// ARetrofitApi
@FormUrlEncoded
@POST("get_favorite_food/{id}")
Call<JsonObject> getFavoriteFood(@Path("id") String userId,
@Field("image") String image,
@Field("name") String foodName);
// BRetrofitApi
@FormUrlEncoded
@POST("get_favorite_sport/{id}")
Call<JsonObject> getFavoriteSport(@Path("id") String userId,
@Field("image") String image,
@Field("name") String sportName);
In You Builder
private static final String BASE_URL = "http://192.168.1.4/myapp/";
private static RetrofitClient mInstance;
private Retrofit retrofit;
private RetrofitClient() {
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static synchronized RetrofitClient getInstance() {
if (mInstance == null) {
mInstance = new RetrofitClient();
}
return mInstance;
}
public ARetrofitApi aGetApi() {
return retrofit.create(ARetrofitApi.class);
}
public BRetrofitApi bGetApi() {
return retrofit.create(BRetrofitApi.class);
}
来电
// Use RetroFit To Feed To MySQL
Call<JsonObject> call = RetrofitClient.getInstance()
.aGetApi()
.getFavoriteFood(userId,
image,
foodName);
// Use RetroFit To Feed To MySQL
Call<JsonObject> call = RetrofitClient.getInstance()
.bGetApi()
.getFavoriteSport(userId,
image,
sportName);
遗憾的是,Retrofit 似乎不支持也不会支持多接口。我很遗憾地说,因为这意味着我们必须开始找出 not-so-optimal 解决方案。
如果对某人有帮助,这是我目前的解决方案(在 Kotlin 中,使用 Moshi 作为转换器):
class MyApi {
companion object {
private val interceptor = HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY)
private val moshiConverterFactory = MoshiConverterFactory
.create(Moshi.Builder().build())
private val retrofit = Retrofit.Builder()
.baseUrl("http://example.com/")
.addConverterFactory(moshiConverterFactory)
.addClient(client)
.build()
val firstApi: MyFirstApi by lazy {
retrofit.create(MyFirstApi::class.java)
}
val secondApi: MySecondApi by lazy {
retrofit.create(MySecondApi::class.java)
}
}
}
如您所见,我正在使用伴随对象来保留单个实例。此外,by lazy
以确保每次调用 firstApi
或 secondApi
时不会调用 create()
。
我正在创建一个链接到 API 的应用程序,其中包含大约 265 种方法。我非常想将这些 API 的声明分解成多个文件,以保持它们的组织性和可访问性。但是 Retrofit 明确禁止通过扩展组合接口。
java.lang.IllegalArgumentException: Interface definitions must not extend other interfaces.
我一直在尝试声明如下。
public interface ApiService extends ProfileService, AccountService {
// Empty interface, methods divided into other services
}
public interface ProfileService {
@GET("/api/v1/protected/profile")
public void getProfile(Callback<Profile> callback);
...
}
public interface AccountService {
@GET("/api/v1/protected/account")
public void getAccount(Callback<Account> callback);
...
}
在拉取请求中有关于此问题的讨论。库作者已经决定像这样扩展接口不符合库的精神。 https://github.com/square/retrofit/pull/676
Jake Wharton(作者)说 "Retrofit favors composition." 并回应 "Do you really have a single adapter with a ton of proxies?","Yes. They are generated from a service declaration in protos. One interface per service."
我一直在阅读有关组合与继承的内容,但未能掌握如何实现分解声明的目标。
如何划分接口声明?是否有我遗漏的最佳实践?
谢谢。
只需创建单独的接口。
public interface ProfileService {
/* ... */
}
public interface AccountService {
/* ... */
}
ProfileService profileService = mRestAdapter.create(ProfileService.class);
AccountService accountService = mRestAdapter.create(AccountService.class);
我仍在试验这是否是使用它的最佳方式,但这是我目前所拥有的。它可能不是最干净的方法,但我喜欢它而不是一个有 100 api 个调用的服务。稍微拆分一下,使其更易于阅读。
这是访问数据的主要class。我已经看到很多将我拥有的两个静态方法分开成一个单独的 class 但我只是将它作为一个包含在内。
public class RetrofitApi {
public enum ApiTypes {
USER_API(UserApi.class);
private final Class<? extends RetrofitApi> apiClass;
ApiTypes(Class<? extends RetrofitApi> apiClass){
this.apiClass = apiClass;
}
Class<? extends RetrofitApi> getApiType() {return this.apiClass;}
}
public static <T> T getApi(RetrofitApi.ApiTypes type) {
try {
return (T) type.getApiType().newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static RestAdapter getRestAdapter() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.setLogLevel(retrofit.RestAdapter.LogLevel.HEADERS)
.build();
return restAdapter;
}
}
每项服务都有自己的 api。这确实意味着更多 classes。我将它们拆分为 api、服务、模型。 API 是您将使用和公开的高级别。服务或多或少只是一个电话列表。而Model就是模型(数据对象)。
public class UserApi extends RetrofitApi {
private UserService service;
public UserApi() {
RestAdapter restAdapter =
RetrofitApi.getRestAdapter();
service = restAdapter.create(UserService.class);
}
public void login(String email,
String password,
Callback<User> callback) {
service.login(email, password, callback);
}
}
服务就是接口。它或多或少只是暴露的 api 个调用列表。
public interface UserService {
@GET("/api/users/login")
void login(@Query("email") String email,
@Query("password") String password,
Callback<User> callback);
}
然后使用它。
UserApi api = RetrofitApi.getApi(RetrofitApi.ApiTypes.USER_API);
api.login(email,password,callback);
这是项目结构。对我来说,目前看起来很干净。我相信当我有 20 多个时,它最终会变大。但是当这 20 个有多个调用时,它可能会更干净一些。
您可以尝试以下方法。
创建2接口class.
- ARetrofitApi
- BRetrofitApi
拨打电话
// ARetrofitApi
@FormUrlEncoded
@POST("get_favorite_food/{id}")
Call<JsonObject> getFavoriteFood(@Path("id") String userId,
@Field("image") String image,
@Field("name") String foodName);
// BRetrofitApi
@FormUrlEncoded
@POST("get_favorite_sport/{id}")
Call<JsonObject> getFavoriteSport(@Path("id") String userId,
@Field("image") String image,
@Field("name") String sportName);
In You Builder
private static final String BASE_URL = "http://192.168.1.4/myapp/";
private static RetrofitClient mInstance;
private Retrofit retrofit;
private RetrofitClient() {
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static synchronized RetrofitClient getInstance() {
if (mInstance == null) {
mInstance = new RetrofitClient();
}
return mInstance;
}
public ARetrofitApi aGetApi() {
return retrofit.create(ARetrofitApi.class);
}
public BRetrofitApi bGetApi() {
return retrofit.create(BRetrofitApi.class);
}
来电
// Use RetroFit To Feed To MySQL
Call<JsonObject> call = RetrofitClient.getInstance()
.aGetApi()
.getFavoriteFood(userId,
image,
foodName);
// Use RetroFit To Feed To MySQL
Call<JsonObject> call = RetrofitClient.getInstance()
.bGetApi()
.getFavoriteSport(userId,
image,
sportName);
遗憾的是,Retrofit 似乎不支持也不会支持多接口。我很遗憾地说,因为这意味着我们必须开始找出 not-so-optimal 解决方案。
如果对某人有帮助,这是我目前的解决方案(在 Kotlin 中,使用 Moshi 作为转换器):
class MyApi {
companion object {
private val interceptor = HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY)
private val moshiConverterFactory = MoshiConverterFactory
.create(Moshi.Builder().build())
private val retrofit = Retrofit.Builder()
.baseUrl("http://example.com/")
.addConverterFactory(moshiConverterFactory)
.addClient(client)
.build()
val firstApi: MyFirstApi by lazy {
retrofit.create(MyFirstApi::class.java)
}
val secondApi: MySecondApi by lazy {
retrofit.create(MySecondApi::class.java)
}
}
}
如您所见,我正在使用伴随对象来保留单个实例。此外,by lazy
以确保每次调用 firstApi
或 secondApi
时不会调用 create()
。