安卓Retrofit设计模式

5
我正在使用 Retrofit 来与我的 REST API 进行交互,想知道是否有任何设计建议。
我的应用程序有以下几个包:
  1. models
  2. services
  3. activities
  4. fragments
其中services包含了 Retrofit 的接口。例如:
public interface FooService {
    @FormUrlEncoded
    @POST("foo/do")
    @Headers("Content-Type: application/x-www-form-urlencoded; charset=UTF-8")
    Call<FooBar> do();
}

模型包含不同的模型,例如FooBar。到目前为止,这与Retrofit文档完全一致。

我创建了一个API类,处理Retrofit构建逻辑(Retrofit retrofit = new Retrofit.Builder()等),并公开了一个静态字段:retrofit。然后在我的活动中,我可以按以下方式执行请求:

FooService service = API.retrofit.create(FooService.class);
Call<FooBar> call = service.do();

try {
    retrofit2.Response response = call.execute();
    // ...do stuff...
} catch(IOException) {}

接下来是我的问题:是否更好地将上述内容进一步抽象化?这样我就不需要到处重复上述内容了吗?例如,像这样的东西:

MyOtherFooService service = new  MyOtherFooService();
FooBar fooBar = service.do();

有什么想法吗?有什么建议?
2个回答

13
我通常使用以下结构的单例模式:

首先定义一个名为ServiceHelper的类,代码如下:

public class ServiceHelper {

private static final String ENDPOINT = "http://test.com";

private static OkHttpClient httpClient = new OkHttpClient();
private static ServiceHelper instance = new ServiceHelper();
private IPlusService service;


private ServiceHelper() {

    Retrofit retrofit = createAdapter().build();
    service = retrofit.create(IPlusService.class);
}

public static ServiceHelper getInstance() {
    return instance;
}

private Retrofit.Builder createAdapter() {

    httpClient.setReadTimeout(60, TimeUnit.SECONDS);
    httpClient.setConnectTimeout(60, TimeUnit.SECONDS);
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    httpClient.interceptors().add(interceptor);

    return new Retrofit.Builder()
            .baseUrl(ENDPOINT)
            .client(httpClient)
            .addConverterFactory(GsonConverterFactory.create());
}

public Call<List<CategoryModel>> getAllCategory() {
    return service.getAllCategory();
}

然后将所有服务放在IService中(在我的情况下是IPlusService

    public interface IPlusService {
    //@Headers( "Content-Type: application/json" ) in Post method may use this
    @GET("/api/category")
    Call<List<CategoryModel>> getAllCategory();
}

然后在您的活动/片段中像以下方式调用您的单例

ServiceHelper.getInstance().getAllCategory().enqueue(new Callback<List<CategoryModel>>() {
        @Override
        public void onResponse(Response<List<CategoryModel>> response, Retrofit retrofit) {
            processResponse(response);
        }

        @Override
        public void onFailure(Throwable t) {
            processResponse(null);
        }
    });

这段代码来自我的以前的项目,它使用的是Retrofit版本:'retrofit:2.0.0-beta2',我认为你应该稍微改一下。 - Amir
这也是我的方法,Amir,正如在Retrofit书中所记录的那样。https://leanpub.com/retrofit-love-working-with-apis-on-android 。我喜欢你没有添加其他东西。KISS :) - Radu
@Radu 真的吗? :D 我两年前就开始使用这种方法了。我是从我的一位同事那里学到的。顺便说一下,感谢你的好方法 ;) - Amir
1
@Amir 不错的代码片段!我稍微扩展了一下你的模式。 - Randika Vishman
1
现在,我的下一个实验是针对这个库RoboSpice https://github.com/stephanenicolas/robospice - Randika Vishman
这是一个无法测试的解决方案,请注意。 - Eido95

1
我建议不要这样做,特别是因为大多数调用需要使用异步的.enqueue并以不同方式处理错误响应。
你可以创建自己的抽象Retrofit回调类,并从中抽象出“自定义”回调,以节省代码重复。
但一般来说,我希望看到应用程序逻辑在发出请求的地方处理响应。
不要陷入过度思考的陷阱,或者应用一些不适合Android的滥用模式。
如果你确实需要从你的活动/片段传递那个响应,只需使用RxJava甚至LocalBroadcast。还可以尝试阅读Retrofit书籍。

1
@Amir 这本书很棒,我推荐每个人都买一本。即使这本书的内容在博客中可以免费获取,但这本书是最好的选择。我建议那位提问的人不要从模式开始。相反,他应该运用常识,在他的活动/片段中使用异步调用。当结果需要广播时,我使用LocalBroadcast或RxJ。 - Radu
谢谢Radu和Amir。稍微相关的问题:你们会推荐为这里使用的所有异步任务创建一个单独的包吗?还是将它们保留为内部类? - JB2
1
@JB2 不要使用异步任务!完全没有必要!你可以使用enqueue方法来实现异步行为! - Radu
@Radu:太酷了!非常棒!:D 谢谢。 - JB2

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