Я пытался решить свою проблему в Google, но до сих пор не понимаю, что делаю не так.
Дело: Существует NetworkModule, который предоставляет все необходимые части для построения объекта Retrofit (он также предоставляется).
Одной из таких частей является Interceptor или OkHttpClient, где для всех запросов установлены HTTP-заголовки.
Пока пользователь приложения не авторизован, я не хочу ничего делать с этим конкретным Interceptor, но как только приложение получит access_token, я хотел бы установить его в Interceptor, чтобы он установил еще один заголовок с этим конкретным access_token.
В ответах Google говорится, что правильный способ сделать это - открыть этот Interceptor, чтобы иметь возможность установить этот access_token, когда мне нужно.
Итак, что я сделал:
Вот мой компонент приложения:
@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()
}
...
}
Но возникает проблема, когда я пытаюсь создать свой модуль «приложение» (Сборка -> Создать модуль «приложение»). При этом возникает ошибка и я не могу понять, что не так.
Вот как выглядит ошибка:
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()
@AndroidTeam да, я использую Dagger2
если вы хотите, предоставьте полную демонстрацию модернизации с помощью Dagger 2.
@AndroidTeam Я не уверен, что подписываюсь на вас. Какая идея разместить демо? Проблема на поверхности :) Все кроме этого нормально
Я предлагаю дооснащение с помощью Dagger 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);
}
сделать компонент api для кинжала 2.
@Singleton @Component (модули = {NetModule.class}) общедоступный интерфейс ApiComponent { void injectApi (действие MainActivity); }
сделать класс уровня приложения ..
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();
}
});
}
}
Приведенный выше код обеспечивает привязку адаптера также там, чтобы вы могли внести изменения в соответствии с.
Это не решает проблему OP и совершенно не связано с вопросом
Эта ошибка возникает из-за того, что вы аннотируете свое поле (val) вместо метода предоставления (getHeaderInterceptor), который Dagger хочет использовать.
Вы можете (должны) правильно объявить метод предоставления:
@Named(NetworkModule.Interceptors.HEADER)
fun provideHeaderInterceptor(): Interceptor
Я не знаю, как и почему вы бы использовали val headerInterceptor, но вы также можете исправить это, объявив аннотацию, которая будет использоваться в получателе
@get:Named(NetworkModule.Interceptors.HEADER")
val foo : Any
вы использовали кинжал 2 для кода.