如何公开组件中模块提供的命名属性

时间:2018-03-30 11:33:24

标签: android dependency-injection retrofit2 dagger-2 okhttp3

我试图围绕我的问题谷歌,但仍然不知道我做错了什么。

案例:有一个NetworkModule,它提供了构建Retrofit对象所需的所有内容(也提供了它)。 其中一个部分是Interceptor OkHttpClient,其中设置了所有请求的HTTP标头。 在应用用户未获得授权之前,我不想对此特定Interceptor执行任何操作,但是一旦应用收到access_token,我就会将其设置为Interceptor,以便它使用此特定access_token设置了另一个标头。

谷歌的答案被认为是一种正确的方法是公开此Interceptor以便能够在需要时设置此access_token。 所以我做了什么:

这是我的AppComponent:

@ApplicationScope
@Component(modules = [
    AppModule::class,
    DataModule::class,
    NetworkModule::class,
    NetworkServicesModule::class,
    RepositoryModule::class,
    SchedulersModule::class])
interface AppComponent{
    /*
    ...
    */

    @Named(NetworkModule.Interceptors.HEADER)
    val headerInterceptor: Interceptor
}

这是一个模块,它提供了这个特殊的拦截器:

@Module
class NetworkModule {
    object Interceptors {
        const val HEADER = "HTTP_HEADER_INTERCEPTOR"
        ...
    }
    ...
    @Provides
    @ApplicationScope
    @Named(Interceptors.HEADER)
    fun provideHeaderInterceptor(): Interceptor {
        return HeaderInterceptor()
    }
    ...
}

但是当我尝试创建我的“app”模块时出现问题(Build - > Make module'app')。 在制作它时,会发生错误,我无法弄清楚出了什么问题。

以下是错误的显示方式:

error: okhttp3.Interceptor cannot be provided without an @Provides-annotated method.
public abstract okhttp3.Interceptor getHeaderInterceptor();
okhttp3.Interceptor is provided at
com.example.app.di.components.AppComponent.getHeaderInterceptor()

2 个答案:

答案 0 :(得分:1)

由于您注释了您的字段(val)而不是Dagger想要使用的提供方法(getHeaderInterceptor),因此会发生此错误。

您可以(应该)正确声明提供方法:

@Named(NetworkModule.Interceptors.HEADER)
fun provideHeaderInterceptor(): Interceptor

我不知道您使用val headerInterceptor的方式或原因,但您也可以通过声明要在getter上使用的注释来修复它 < / p>

@get:Named(NetworkModule.Interceptors.HEADER")
val foo : Any

答案 1 :(得分:-3)

我使用匕首2提供改装。 制作网络模块..

@Module

public class NetModule {     String baseUrl;

public NetModule(String baseUrl) {
    this.baseUrl = baseUrl;
}

@Provides
@Singleton
OkHttpClient provideOkhttpClient(Context context) {
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient.Builder client = new OkHttpClient.Builder();
    client.readTimeout(20, TimeUnit.SECONDS);
    client.writeTimeout(20,TimeUnit.SECONDS);
    client.connectTimeout(20, TimeUnit.SECONDS);
    client.addInterceptor(interceptor);
    client.addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (context == null) {
                request = request
                        .newBuilder()
                        .build();
            } else {
                request = request
                        .newBuilder()
                        .addHeader("Authorization", "Bearer " + AppSetting.getStringSharedPref(context, Constants.USER_KEY_TOKEN, ""))
                        .build();
            }
            return chain.proceed(request);
        }
    });
    return client.build();
}
@Provides
@Singleton
Retrofit getRetrofit(){
    return new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(baseUrl)
            .client(provideOkhttpClient())
            .build();

}

}

为api调用创建接口..

public interface Api {
@GET("marvel/")
Call<List<Hero>> getHero();
@GET("/users")
Call<List<User>> getUser(@Query("since") int since, @Query("per_page") int perPage);

}

为匕首2制作api组件。

@Singleton @Component(modules = {NetModule.class}) 公共接口ApiComponent {     void injectApi(MainActivity activity);  }

制作应用程序级别..

public class AppActivity extends Application {
private ApiComponent component;

@Override
public void onCreate() {
    super.onCreate();
    component = DaggerApiComponent.builder()
            .netModule(new NetModule("https://api.github.com")).build();
}

public ApiComponent getComponent() {
    return component;
}

}

在应用程序xml标记中的清单文件中定义此类..

        android:name=".AppActivity"

然后将改装对象注入活动类后..

public class MainActivity extends AppCompatActivity {
private Button mBtnCallWs;
private ListView mLvData;
@Inject
Retrofit retrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ((AppActivity)getApplication()).getComponent().injectApi(this);

    initView();
}

private void initView() {
    mBtnCallWs=findViewById(R.id.amBtnCall);
    mLvData=findViewById(R.id.amLvData);
    mBtnCallWs.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            getHeroes();
        }
    });
}

private void getHeroes() {
    Api api = retrofit.create(Api.class);
    Call<List<Hero>> call = api.getHero();

    call.enqueue(new Callback<List<Hero>>() {
        @Override
        public void onResponse(Call<List<Hero>> call, Response<List<Hero>> response) {
            List<Hero> heroList = response.body();
            String[] heroes = new String[heroList.size()];

            for (int i = 0; i < heroList.size(); i++) {
                heroes[i] = heroList.get(i).getName();
            }

            mLvData.setAdapter(new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, heroes));
        }

        @Override
        public void onFailure(Call<List<Hero>> call, Throwable t) {
            Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });
}

}

上面的代码也提供了适配器绑定,您可以根据需要进行更改。