【问题标题】:Best practices of using Retrofit2 (multiple service)使用 Retrofit2(多服务)的最佳实践
【发布时间】:2018-12-03 14:41:09
【问题描述】:

我正在使用 Kotlin 编写一个集成 Retrofit2 的 Android 应用。

据我了解(如果我错了,请纠正我),这样做的“传统”方式是:

  1. 创建一个接口,其中包括我所有 API 的方法定义。
  2. 使用 retrofit.create() 将其传递给改造,它为我实现了它,然后我可以使用步骤 #1 中的函数访问所有这些

看了this之后,我的问题是: 为我的每个请求创建单独的接口是否更好?

例如如果我有一个“LoginRequest”,并如下所示实现它(“create”本质上调用retrofit.create()),下次我想添加/删除API时,我只需要添加/删除1个文件,而不是几个地方(请求本身、步骤#1 中的服务,以及使用步骤#2 中的方法的所有地方)。另一方面,这会导致我的应用程序“知道”retrofit2,我也不确定这是否是一个好习惯。

interface MyRequest {
    fun execute()
}

class LoginRequest (private val email: String, private val password: String) : MyRequest {
    interface LoginRequestService {
        @POST("login")
        fun emailLogin(
                @Body loginRequestBody: LoginRequestBody):
                retrofit2.Call<GetUserDetailsResponse>
    }

    override fun execute() {
        val requestBody = LoginRequestBody(email, password)
        val call = MyRequestManager.create(LoginRequestService::class.java).emailLogin(requestBody)
        MyRequestManager.executeCall(call)
    }
}

【问题讨论】:

  • 我以前从未见过改造的这种实现。遵循官方指南有什么问题? square.github.io/retrofit
  • 我想这里的一件好事(?)是您可以避免一个单一的服务定义接口文件,并且一切都可以分开。但是,与其将服务作为执行的一部分,它应该是类的静态成员
  • Is it a better practice to create a separate interface for each of my requests? 不,我以前做过,然后花了一些时间将它们重新组合在一起。只有为每个 baseUrl(或不同的 OkClients)创建一个接口才有意义。
  • 另外,根据请求创建一个新的改造实现绝对不是一个更好的做法。

标签: android kotlin retrofit2


【解决方案1】:

如果你遵循官方指南https://square.github.io/retrofit/会更好

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}


Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();



GitHubService service = retrofit.create(GitHubService.class);

Call<List<Repo>> repos = service.listRepos("octocat");

那么您可以为服务提供一个 Singleton 以便更轻松,我还喜欢为每个调用创建接口,如下所示,将在我想要的任何类中使用。

interface IListRepos {
    fun listRepos(user: String, onResponse: (MutableList<Repo>?) -> Unit) {
        ServiceSingleton.client.create(GitHubService::class.java)
                .listRepos(user)
                .enqueue(object : Callback<MutableList<Repo>> {
                    override fun onResponse(call: Call<MutableList<Repo>>,
                                            response: retrofit2.Response<MutableList<Repo>>) {
                        onResponse(response.body())
                    }

                    override fun onFailure(call: Call<MutableList<Repo>>, t: Throwable) {
                        onResponse(null)
                    }
                })
    }
}

【讨论】:

    【解决方案2】:

    我在java中做的方式 为所有人提供 1 个接口,带有单独的请求。

    里面

    public interface ApiInterface {
    }
    

    我已将所有网址设置在 1 个位置,以便以后轻松编辑

    String Base_Url = "http://url.com/store/web/app_dev.php/api/";
    String Base_Url_Channel = "http://url.com/store/web/app_dev.php/api/APP_STORE/";
    String Image_URL_Online = "http://url.com/store/web/media/image/";
    

    对于retrofit2方法调用类

    public class DataServiceGenerator {
    
        public static <S> S createService(Class<S> serviceClass) {
    
            String url = ApiInterface.Base_Url;
            Retrofit.Builder builder = new Retrofit.Builder()
                    .addConverterFactory(GsonConverterFactory.create())
                    .baseUrl(url);
    
            OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
                    .readTimeout(15, TimeUnit.SECONDS)
                    .connectTimeout(15, TimeUnit.SECONDS)
                    .writeTimeout(25, TimeUnit.SECONDS);
    
            if (BuildConfig.DEBUG) {
                HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor()
                        .setLevel(HttpLoggingInterceptor.Level.BODY);
                httpClient.addInterceptor(interceptor);
                httpClient.addNetworkInterceptor(new StethoInterceptor()); // for debugging
            }
            builder.client(httpClient.build());
            Retrofit retrofit = builder.build();
            return retrofit.create(serviceClass);
        }
     }
    

    现在在接口中使用下面的方法调用 API 即时通讯

    @Multipart
    @Headers("Accept: Application/json")
    @POST("oauth/v2/token")
    Call<Token_Model> token(
            @Part("client_id") RequestBody id,
            @Part("client_secret") RequestBody secret,
            @Part("grant_type") RequestBody username,
            @Part("username") RequestBody name,
            @Part("password") RequestBody password);
    

    对于方法本身:

    Call<Token_Model> call = service.token(createPartFromString("13123khkjhfsdf"),
                    createPartFromString("1asd234k234lkh24"),
                    createPartFromString("password"), createPartFromString("api@example.com"), createPartFromString("test"));
            call.enqueue(new Callback<Token_Model>() {
                @Override
                public void onResponse(Call<Token_Model> call, retrofit2.Response<Token_Model> response) {
                    if (response.isSuccessful()) {
                        token_model = response.body();
                        if (token_model != null) {
                            helper.setToken(token_model.getAccess_token());
                        }
    
                    } else {
                        Toast.makeText(context, context.getString(R.string.failed_token), Toast.LENGTH_LONG).show();
                    }
                }
    
                @Override
                public void onFailure(Call<Token_Model> call, Throwable t) {
                    Toast.makeText(context, context.getString(R.string.failed_token), Toast.LENGTH_LONG).show();
                }
            });
    

    【讨论】:

    • 请注意,您可以复制我的代码并将其转换为 kotlin
    • 这意味着每次调用 API 时,该调用的接口都会传递给改造,然后改造实现它。对吗?
    • 你不必实现其他任何东西,这是完整的工作代码
    • 您将在改造方法 (onResponse) 中回电
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-27
    • 1970-01-01
    • 1970-01-01
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多