Reputation: 2229
I am trying to use dagger 2 to inject dependencies in a fragment in my application
I have the following modules
Network Module
@Module(includes = ContextModule.class)
public class NetworkModule {
@Provides
Cache getCacheFile(Context context) {
File cacheFile = new File(context.getCacheDir(), "okhttp-cache");
return new Cache(cacheFile, 10 * 1000 * 1000);
}
@Provides
HttpLoggingInterceptor getHttpLoggingInteceptor() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
return logging;
}
@Provides
OkHttp3Downloader getOkHttp3Downloader(Context context) {
return new OkHttp3Downloader(context);
}
@Provides
OkHttpClient getOkHttpClient(HttpLoggingInterceptor interceptor, Cache cache) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newBuilder().cache(cache)
.addInterceptor(interceptor)
.build();
return okHttpClient;
}
@Provides
Retrofit getRetrofit(OkHttpClient client, GsonConverterFactory gsonConverterFactory, RxJava2CallAdapterFactory callAdapter) {
return new Retrofit.Builder()
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(callAdapter)
.baseUrl("https://api.themoviedb.org/3/")
.client(client)
.build();
}
@Provides
GsonConverterFactory getGsonConverterFactory() {
return GsonConverterFactory.create();
}
@Provides
RxJava2CallAdapterFactory getRxJavaFactory() {
return RxJava2CallAdapterFactory.create();
}
}
ActivityBuilder Module
@Module
public abstract class ActivityBuilder {
@ContributesAndroidInjector
abstract NewsListActivity bindMoviesListActivity();
@ContributesAndroidInjector(modules = NewsListFragmentModule.class)
abstract NewsListFragment bindNewsListFragment();
}
Here is the AppComponent
@Component(modules = {AndroidSupportInjectionModule.class, ContextModule.class, ActivityBuilder.class})
public interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(NewsApp app);
}
This is my activity class where the fragment is embedded
class NewsListActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener, HasSupportFragmentInjector {
@Inject
lateinit var mAndroidInjector: AndroidInjector<Fragment>
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_news_list)
setSupportActionBar(toolbar)
val toggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
drawer_layout.addDrawerListener(toggle)
toggle.syncState()
nav_view.setNavigationItemSelectedListener(this)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.frame_main, NewsListFragment(), "news-list-fragment")
.commit()
}
}
override fun supportFragmentInjector(): AndroidInjector<Fragment> {
return mAndroidInjector
}
}
And finally this is my Fragment class
class NewsListFragment : Fragment() {
lateinit var picasso: Picasso
@Inject
lateinit var newsService: NewsService
@Inject
lateinit var newsFragmentViewModel: NewsFragmentViewModel
lateinit var newsListAdapter: NewsListAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_news_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
swipe_layout.setColorSchemeColors(resources.getColor(R.color.orange),resources.getColor(R.color.green),resources.getColor(R.color.blue))
newsListAdapter = NewsListAdapter(newsItemClickListener, picasso)
val layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
rv_news_top_headlines.layoutManager = layoutManager
rv_news_top_headlines.setHasFixedSize(true)
rv_news_top_headlines.adapter = newsListAdapter
newsFragmentViewModel = ViewModelProviders.of(this).get(NewsFragmentViewModel::class.java)
swipe_layout.isRefreshing = true
newsFragmentViewModel.init(newsService)
loadDataFromApi()
swipe_layout.setOnRefreshListener {
loadDataFromApi()
}
}
private fun loadDataFromApi() {
// Load data from API
}
override fun onAttach(context: Context?) {
AndroidSupportInjection.inject(this)
super.onAttach(context)
}
private val newsItemClickListener = fun(article: Articles) {
toast(article.title.toString())
}
}
I followed many different tutorials to find out how to use the new AndroidInjection in Fragments so I don't have the links of those tutorials?
Is there anything I'm doing wrong?
The error
e: /Users/sriramr/Desktop/android/NewsApp/app/src/main/java/in/sriram/newsapp/di/AppComponent.java:12: error: [dagger.android.AndroidInjector.inject(T)] dagger.android.AndroidInjector<android.support.v4.app.Fragment> cannot be provided without an @Provides- or @Produces-annotated method.
public interface AppComponent {
^
dagger.android.AndroidInjector<android.support.v4.app.Fragment> is injected at
in.sriram.newsapp.ui.newslist.NewsListActivity.mAndroidInjector
in.sriram.newsapp.ui.newslist.NewsListActivity is injected at
dagger.android.AndroidInjector.inject(arg0)
Upvotes: 0
Views: 821
Reputation: 3480
Try to change following in NewsListActivity
AndroidInjector<Fragment>
to:
DispatchingAndroidInjector<Fragment>
Also You haven't posted your application class. Make sure it has following things:
class NewsApp : Application(), HasActivityInjector {
@Inject
lateinit var activityDispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
override fun onCreate() {
super.onCreate()
DaggerAppComponent.builder()
.application(this)
.build()
.inject(this)
// some other initialization
}
fun activityInjector(): AndroidInjector<Activity>? {
return activityDispatchingAndroidInjector
}
}
Upvotes: 1