【问题标题】:Android, MVP, Dagger 2 and Retrofit with multiple data sources具有多个数据源的 Android、MVP、Dagger 2 和 Retrofit
【发布时间】:2017-09-29 00:32:29
【问题描述】:

我有三个数据源:

  • JSON API
  • Github
  • XML 清单

我正在使用 Retrofit 和 OkHttp 等来访问所有这些:

  • JSON API 使用 Gson 反序列化
  • XML Manifest 返回一个字符串,我将对其进行反序列化
  • Github 返回我显示的字符串

JSON 和 XML 将使用相同的实体进行反序列化。因此,我想将我的 MVP 代码编写得足够抽象,以至于它只需要实体。

所以,我为此写了一个界面

public interface BaseRomRepository {
    // Addons
    Call<List<AddonEntity>> getAddons(String slug);
    Call<List<AddonEntity>> getAddons(int id);

    Call<AddonEntity> getAddon(String slug);
    Call<AddonEntity> getAddon(int id);

    // Versions
    Call<List<VersionEntity>> getVersions(String slug);
    Call<List<VersionEntity>> getVersions(int id);

    Call<VersionEntity> getVersion(String slug);
    Call<VersionEntity> getVersion(int id);
}

所以,我的 Presenters 和 Interactors 可以简单地调用这些方法,它应该取决于实际使用 Repository 的实现。

但是,这就是我卡住的地方。我不确定使用 Dagger 2 执行此操作的最佳方法。我确信它适合此用例,但我正在努力弄清楚在哪里/如何执行此操作。

我说得对吗?存储库和反序列化轻松地存在于 MVP 模型中。所有这些都应该在那里发生,Presenter 层可能相对不知道正在使用哪个存储库?

我会展示更多代码,但它非常混乱,我现在很难抽象成更易读的方式。

编辑:

这是一个 Gist,其中包含我到目前为止的一些实现:https://gist.github.com/MatthewBooth/e3dd7a1f3a19fa0fd18e811752170be6

【问题讨论】:

    标签: android retrofit2 dagger-2 okhttp3 android-mvp


    【解决方案1】:

    如果你想为同一个接口提供不同的实现,你可以创建一个@Module类,并使用@Named注解。

    在你的模块中:

    @Provides
    @Named("xmlRepository")
    BaseRomRepository provideXmlRepository() {
        return new XmlRepository();
    }
    
    @Provides
    @Named("restRepository")
    BaseRomRepository provideRestRepository() {
        return new RestRepository();
    }
    
    @Provides
    @Named("githubRepository")
    BaseRomRepository provideGithubRepository() {
        return new GithubRepository();
    }
    

    这样你就可以在代码中简单地使用:

    @Inject
    @Named("xmlRepository")
    BaseDomRepository xmlRepo;
    @Inject
    @Named("githubRepository")
    BaseDomRepository githubRepo;
    @Inject
    @Named("restRepository")
    BaseDomRepository restRepo;
    

    或者在你的模块中

    @Provides
    @Singleton
    AddonInteractor providesAddonInteractor(@Named("xmlRepository") BaseRomRepository repository) {
        return new AddonInteractorImpl<>(repository);
    }
    

    编辑:我会保留上面的内容,因为我认为它对其他人有用。

    当我们在评论中进一步深入研究时,似乎 OP 想要一种不同的方法。

    您不需要@Named 注释。此类情况使用应用程序变体处理。您创建了 3 种应用风格:rest、xml、github。您将所有代码保存在main 中。然后你放了 3 个实现,比如说RepositoryModule,每个都实例化你的BaseDomRepository 的正确版本。

    看到这个:https://developer.android.com/studio/build/build-variants.html

    【讨论】:

    • 我也建议使用单例的范围来避免作用域!
    • 这取决于实际的应用程序和架构,绝对不适用于任何应用程序。有时您想在以下情况下替换您的数据提供者:另一个用户登录、您选择不同的订阅等。范围是不同的主题。
    • 在这种情况下其实你想要的,考虑在应用的生命周期内返回相同的类型,它会如何应对呢,
    • 我认为我们在这里缺乏信息来决定我们是否需要适当的范围界定或单例可以。
    • 我认为我们同意,
    【解决方案2】:

    考虑在 dagger2 中使用命名和单例注释。

    @Module
    public class BasicModule {
    
        @Provides
        @Named("basic")
        @Singleton
        public BasicServer provideBasicServer() {
            return new BasicServer();
        }
    
        @Provides
        @Named("basic")
        @Singleton
        public BasicServer provideBasicServer() {
            return new BasicServer();
        }
    }
    

    如果我们需要两个具有相同返回类型的不同对象,我们可以使用@Named 限定符注解。您将在提供单例的位置(@Provides 注释)和注入它们的位置(@Inject 注释)定义它:

    【讨论】:

    • 命名注解,@Named用于区分2个相同类型的对象,从而区分名称和返回类型
    • @Singleton注解用于向Dagger声明在应用的整个生命周期内只初始化一次
    猜你喜欢
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    • 1970-01-01
    • 2018-01-02
    • 2017-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多