简体   繁体   中英

Android, MVP, Dagger 2 and Retrofit with multiple data sources

I have three data sources:

  • A JSON API
  • Github
  • An XML manifest

I'm using Retrofit, with OkHttp etc, to access all of them as such:

  • JSON API is deserialised with Gson
  • XML Manifest returns a string, which I will deserialise
  • Github returns a string which I display

The JSON and XML will deserialise using the same Entities. As such I'd like to write my MVP code to be abstract enough that it just expects the entities.

So, I wrote an interface for this

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);
}

So, my Presenters and Interactors can simply call these methods and it should depend on the implementation on which Repository is actually used.

However this is where I'm stuck. I'm unsure on the best way to do this with Dagger 2. I'm sure it lends itself to this use case but I'm struggling to figure out where/how to do this.

Am I right with this? The repositories and the deserialisation comfortably live within the Model of MVP. All that should happen there and the Presenter layer can be relatively unaware of which repository is being used?

I'd show more code but it's very messy and would be hard for me to abstract into a more readable way right now.

EDIT:

Here's a Gist containing some of the implmentations I've got so far: https://gist.github.com/MatthewBooth/e3dd7a1f3a19fa0fd18e811752170be6

If you want to provide different implementations of the same interface you can create a @Module class, and use @Named annotations.

In your module:

@Provides
@Named("xmlRepository")
BaseRomRepository provideXmlRepository() {
    return new XmlRepository();
}

@Provides
@Named("restRepository")
BaseRomRepository provideRestRepository() {
    return new RestRepository();
}

@Provides
@Named("githubRepository")
BaseRomRepository provideGithubRepository() {
    return new GithubRepository();
}

That way in code you can simply use:

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

Or in your module

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

EDIT: I'm gonna keep what's above, cause I think it can be useful for someone else.

As we dug into it a bit further in the comment it seems OP wants a different approach.

You don't need @Named annotations. Such cases are handled using Application Variants. You create 3 app flavors: rest, xml, github. You keep all of your code in main . Then you put 3 implementations of, let's say RepositoryModule , each of which instantiates the proper version of your BaseDomRepository .

See this: https://developer.android.com/studio/build/build-variants.html

consider using the named and singleton annotations In 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();
    }
}

If we need two different objects of the same return type, we can use the @Named qualifier annotation. You will define it both where you provide the singletons ( @Provides annotation), and where you inject them ( @Inject annotations):

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM