Кинжал 2 впрыскивает два модифицированных объекта - PullRequest
0 голосов
/ 03 июня 2018

Я использую Dagger 2 с библиотекой retrofit2 при использовании MVP.Все шло хорошо, пока я не попытался интегрировать другой сервис (в основном я попытался инициализировать другой объект дооснащения другим сервисом).Я следовал за этим ответом , но безуспешно.

Каждый раз, когда я получаю сообщение об ошибке, что каждый из моих фрагментов и классов приложений, похоже, не распознает классы компонентов.

ошибка: не удается найти класс символов DaggerApplicationComponent ошибка: не удается найти класс символов DaggerEpisodeComponent

Код

ApplicationComponent

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

    Retrofit exposeStreamingRetrofit();

    Retrofit exposeRetrofit();

    Context exposeContext();

    AppPreferenceHelper exposePrefs();

}

Прикладной модуль

   @Module
public class ApplicationModule
{
    private String mBaseUrl;
    private Context mContext;
    private AppPreferenceHelper mPrefsHelper;

    public ApplicationModule(Context context,String baseUrl)
    {
        mContext = context;
        mBaseUrl = baseUrl;
        mPrefsHelper = new AppPreferenceHelper(context, Consts.PREF_NAME);
    }


    @Singleton
    @Provides
    GsonConverterFactory provideGsonConverterFactory()
    {
        GsonConverterFactory gsonConverterFactory = GsonConverterFactory.create();
        return gsonConverterFactory;
    }

    @Singleton
    @Provides
    @Named("ok-1")
    OkHttpClient provideOkHttpClient()
    {

        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);

        return new OkHttpClient().newBuilder()
                .connectTimeout(500, TimeUnit.MILLISECONDS)
                .readTimeout(500,TimeUnit.MILLISECONDS)
                .addInterceptor(logging)
                .build();
    }

    @Singleton
    @Provides
    RxJava2CallAdapterFactory provideRxJava2CallAdapterFactory()
    {
        return RxJava2CallAdapterFactory.create();
    }

    @Provides
    @Singleton
    Retrofit provideRetrofit(@Named("ok-1") OkHttpClient client, GsonConverterFactory convectorFactory, RxJava2CallAdapterFactory adapterFactory)
    {
        return new Retrofit.Builder()
                .baseUrl(mBaseUrl)
                .addConverterFactory(convectorFactory)
                .addCallAdapterFactory(adapterFactory)
                .client(client)
                .build();
    }

    @Provides
    @Singleton
    Retrofit provideStreamingRetrofit(@Named("ok-1") OkHttpClient client, GsonConverterFactory convectorFactory, RxJava2CallAdapterFactory adapterFactory) {
        return new Retrofit.Builder()
                .baseUrl(Consts.STREAMING_BASE_PATH)
                .addConverterFactory(convectorFactory)
                .addCallAdapterFactory(adapterFactory)
                .client(client)
                .build();
    }

    @Singleton
    @Provides
    Context provideContext()
    {
        return mContext;
    }

    @Singleton
    @Provides
    AppPreferenceHelper provideAppPreferenceHelper(){
        return mPrefsHelper;
    }

}

StreamingService

public interface StreamingService
{
    @GET("search")
    Observable<StreamingItems> getStreamingItems(@Query("keyword") String query);
}

Потоковый модуль @ Модуль

public class StreamingModule
{
    private StreamingView mView;

    public StreamingModule(StreamingView view)
    {
        mView = view;
    }

    @PerFragment
    @Provides
    StreamingService provideStreamingService(Retrofit retrofit)
    {
        return retrofit.create(StreamingService.class);
    }

    @PerFragment
    @Provides
    StreamingView provideView()
    {
        return mView;
    }

    public void disposeView()
    {
        mView = null;
    }
}

Потоковый компонент

@PerFragment
@Component(modules = StreamingModule.class, dependencies = ApplicationComponent.class)
public interface StreamingComponent {
    void inject(StreamingFragment streamingFragment);
}

Streaming Presenter

public class StreamingPresenter extends BasePresenter<StreamingView>
{
    private long                    mMaxPagesOfTopSeries;

    @Inject
    protected StreamingService mApiService;

    @Inject
    protected Mapper                mTopSeriesMapper;

    @Inject
    protected AppPreferenceHelper   mPrefsHelper;

    @Inject
    public StreamingPresenter()
    {
        mMaxPagesOfTopSeries = 1;

    }
}

Возможно, проблема связана с экспонированием другогоэкземпляр Retrofit в классе приложения компонента, но я не уверен.

Обновление 1

EpisodeModule

@PerFragment
@Component (modules = EpisodeModule.class, dependencies = ApplicationComponent.class)
public interface EpisodeComponent
{
    void inject(EpisodeFragment episodeFragment);
}

После создания потоковых классов (служба, презентатор, модуль, компонент) Я ничего не изменил в других классах, поэтому я думаю, что проблема где-то в модуле / компоненте приложения или потоковых классах, но я не уверен, потому что я мог бы изменить объект модификации для других фрагментов, потому что я добавил новый экземпляр модернизациидля потоковой передачи.

Ответы [ 2 ]

0 голосов
/ 15 сентября 2018

Вы можете использовать аннотацию @Named, как описано @ilosqu, но я не могу обойтись без использования магических строк и получающегося в результате запаха кода.В большом проекте со множеством экземпляров Retrofit разработчики должны помнить или, что хуже, искать значения Name каждый раз, когда требуется экземпляр.Это кажется утомительным, неуправляемым в масштабе и трудным для рефакторинга.Я здесь не осуждаю, я просто хочу высказать свое обоснование другого подхода.

Мое решение (Kotlin) состояло в том, чтобы создать уникальные классы для каждого экземпляра Retrofit, аналогичные идее маркерных интерфейсов в Java.Поскольку Retrofit является конечным классом и не предоставляет никаких интерфейсов, обеспечивающих простое расширение, вместо этого был вынужден создать абстрактный класс-обертку, обеспечивающий тот же результат.

/**
 * This abstract class allows for extension and can expose 
 * convenience functions to Retrofit functionality by composition
 */

abstract class RetrofitContainer(private val retrofit: Retrofit) {
    fun <T> create(service: Class<T>): T {
        return retrofit.create(service)
    }

    fun getRetrofit(): Retrofit {
        return retrofit
    }
}

Для каждого уникального экземпляра Retrofit вам потребуетсядля создания конкретного класса, расширяющего RetrofitContainer.

/**
 * This class can be injected anywhere you want the Streaming Retrofit instance
 */
class StreamingRetrofit(retrofit: Retrofit): RetrofitContainer(retrofit)

Теперь в ваших модулях вы можете создавать методы @Provides для каждого класса «маркера» и внедрять их через класс без необходимости @ Named

@Provides
@Singleton
fun provideStreamingService(retrofit: StreamingRetrofit): StreamingService{
    return retrofit.create(StreamingService::class.java)
}

@Provides
@Singleton
fun provideStreamingRetrofit(
        client: OkHttpClient,
        adapterFactory: RxJava2CallAdapterFactory,
        converterFactory: GsonConverterFactory
): StreamingRetrofit {
    val retrofit = Retrofit.Builder()
            .baseUrl(Consts.STREAMING_BASE_PATH)
            .addConverterFactory(convectorFactory)
            .addCallAdapterFactory(adapterFactory)
            .client(client)
            .build();

    return StreamingRetrofit(retrofit)
}

Эта техника позволяет осуществлять краткий поиск и рефакторинг без необходимости запоминать магию.Вероятно, в большинстве случаев можно использовать тот же подход, что в противном случае вам понадобится использовать экземпляры @Named.

0 голосов
/ 07 июня 2018

Вы правы, проблема - это второй обнаруженный экземпляр Retrofit в модуле приложения. Решение состоит в том, чтобы использовать квалификаторы кинжалов.Просто замените соответствующие блоки кода на:

Определите поставщика модернизации с помощью квалификатора @Named("streaming") в Прикладной модуль

@Provides
@Singleton
@Named("streaming")
Retrofit provideStreamingRetrofit(@Named("ok-1") OkHttpClient client, GsonConverterFactory convectorFactory, RxJava2CallAdapterFactory adapterFactory) {
    return new Retrofit.Builder()
            .baseUrl(Consts.STREAMING_BASE_PATH)
            .addConverterFactory(convectorFactory)
            .addCallAdapterFactory(adapterFactory)
            .client(client)
            .build();
}

Не забывайте выставлять экземпляр модернизации с точно таким жеквалификатор в прикладной компонент

@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {

    @Named("streaming") Retrofit exposeStreamingRetrofit();

    Retrofit exposeRetrofit();

    Context exposeContext();

    AppPreferenceHelper exposePrefs();

}

Всякий раз, когда вам нужен экземпляр модернизации службы потоковой передачи - не забудьте установить квалификатор.Пример в Потоковый модуль

@PerFragment
@Provides
StreamingService provideStreamingService(@Named("streaming") Retrofit retrofit) {
    return retrofit.create(StreamingService.class);
}
...