Skip to content

Commit

Permalink
Part 10: Adding Dagger 2
Browse files Browse the repository at this point in the history
  • Loading branch information
juanchosaravia committed Jul 20, 2016
1 parent c72868a commit 296a7bc
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 22 deletions.
9 changes: 8 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ android {
main.java.srcDirs += 'src/main/kotlin'
}
}

kapt {
generateStubs = true
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
Expand All @@ -42,6 +44,11 @@ dependencies {
compile 'com.squareup.retrofit2:retrofit:2.0.0'
compile 'com.squareup.retrofit2:converter-moshi:2.0.0'

// Dagger 2
compile 'com.google.dagger:dagger:2.4'
kapt 'com.google.dagger:dagger-compiler:2.4'
provided 'org.glassfish:javax.annotation:10.0-b28'

// Tests
testCompile 'org.mockito:mockito-core:1.+'
testCompile 'org.jetbrains.spek:spek:1.0.+'
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.droidcba.kedditbysteps">

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".KedditApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
Expand Down
25 changes: 25 additions & 0 deletions app/src/main/java/com/droidcba/kedditbysteps/KedditApp.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.droidcba.kedditbysteps

import android.app.Application
import com.droidcba.kedditbysteps.di.AppModule
import com.droidcba.kedditbysteps.di.news.DaggerNewsComponent
import com.droidcba.kedditbysteps.di.news.NewsComponent

/**
*
* @author juancho.
*/
class KedditApp : Application() {

companion object {
lateinit var newsComponent: NewsComponent
}

override fun onCreate() {
super.onCreate()
newsComponent = DaggerNewsComponent.builder()
.appModule(AppModule(this))
//.newsModule(NewsModule()) Module with empty constructor is implicitly created by dagger.
.build()
}
}
18 changes: 3 additions & 15 deletions app/src/main/java/com/droidcba/kedditbysteps/api/NewsRestAPI.kt
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
package com.droidcba.kedditbysteps.api

import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import javax.inject.Inject

class NewsRestAPI() : NewsAPI {

private val redditApi: RedditApi

init {
val retrofit = Retrofit.Builder()
.baseUrl("https://www.reddit.com")
.addConverterFactory(MoshiConverterFactory.create())
.build()

redditApi = retrofit.create(RedditApi::class.java)
}
class NewsRestAPI @Inject constructor(private val redditApi: RedditApi) : NewsAPI {

This comment has been minimized.

Copy link
@danielgomezrico

danielgomezrico Jan 4, 2017

Contributor

Why @Inject for constructor and not lateinit?

This comment has been minimized.

Copy link
@juanchosaravia

juanchosaravia Jan 26, 2017

Author Owner

@caipivara not sure if it will allow you to have the redditApi as private. Do you know if using lateinit can be private?

This comment has been minimized.

Copy link
@felipefpx

felipefpx May 21, 2017

@juanchosaravia and @caipivara, I think lateinit is not needed for constructors because it does a static initialization, converting the properties and its initializations for something like this:

class Dog {
var name: String
init {
name = "Little Dog"
}
}

This comment has been minimized.

Copy link
@danielgomezrico

danielgomezrico May 21, 2017

Contributor

@juanchosaravia 👍 you need that in order to have it private.
@felipefpx you can use val if is just initialized once (if just in constructor)


override fun getNews(after: String, limit: String): Call<RedditNewsResponse> {
return redditApi.getTop(after, limit)
}
}
}
27 changes: 27 additions & 0 deletions app/src/main/java/com/droidcba/kedditbysteps/di/AppModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.droidcba.kedditbysteps.di

import android.content.Context
import com.droidcba.kedditbysteps.KedditApp
import dagger.Module
import dagger.Provides
import javax.inject.Singleton

/**
*
* @author juancho.
*/
@Module
class AppModule(val app: KedditApp) {

@Provides
@Singleton
fun provideContext(): Context {

This comment has been minimized.

Copy link
@johanneslagos

johanneslagos Mar 21, 2017

You could also write it like this:
fun provideContext(): Context = app

This comment has been minimized.

Copy link
@juanchosaravia

juanchosaravia Mar 22, 2017

Author Owner

That's right! if you can, please send a PR 👍

return app;
}

@Provides
@Singleton
fun provideApplication(): KedditApp {
return app;
}
}
24 changes: 24 additions & 0 deletions app/src/main/java/com/droidcba/kedditbysteps/di/NetworkModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.droidcba.kedditbysteps.di

import dagger.Module
import dagger.Provides
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import javax.inject.Singleton

/**
*
* @author juancho.
*/
@Module
class NetworkModule {

@Provides
@Singleton
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://www.reddit.com")
.addConverterFactory(MoshiConverterFactory.create())
.build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.droidcba.kedditbysteps.di.news

import com.droidcba.kedditbysteps.di.AppModule
import com.droidcba.kedditbysteps.di.NetworkModule
import com.droidcba.kedditbysteps.features.news.NewsFragment
import dagger.Component
import javax.inject.Singleton

/**
*
* @author juancho.
*/
@Singleton
@Component(modules = arrayOf(
AppModule::class,

This comment has been minimized.

Copy link
@csv8674xn

csv8674xn Dec 11, 2017

Why does NewsComponent have dependency on AppModule ?

NewsModule::class,
NetworkModule::class)
)
interface NewsComponent {

fun inject(newsFragment: NewsFragment)

}
34 changes: 34 additions & 0 deletions app/src/main/java/com/droidcba/kedditbysteps/di/news/NewsModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.droidcba.kedditbysteps.di.news

import com.droidcba.kedditbysteps.api.NewsAPI
import com.droidcba.kedditbysteps.api.NewsRestAPI
import com.droidcba.kedditbysteps.api.RedditApi
import dagger.Module
import dagger.Provides
import retrofit2.Retrofit
import javax.inject.Singleton

/**
*
* @author juancho.
*/
@Module
class NewsModule {

@Provides
@Singleton
fun provideNewsAPI(redditApi: RedditApi): NewsAPI {
return NewsRestAPI(redditApi)
}

@Provides
@Singleton
fun provideRedditApi(retrofit: Retrofit): RedditApi {
return retrofit.create(RedditApi::class.java)
}

/**
* NewsManager is automatically provided by Dagger as we set the @Inject annotation in the
* constructor, so we can avoid adding a 'provider method' here.
*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.support.v7.widget.LinearLayoutManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.droidcba.kedditbysteps.KedditApp
import com.droidcba.kedditbysteps.R
import com.droidcba.kedditbysteps.commons.InfiniteScrollListener
import com.droidcba.kedditbysteps.commons.RedditNews
Expand All @@ -15,15 +16,21 @@ import com.droidcba.kedditbysteps.features.news.adapter.NewsAdapter
import kotlinx.android.synthetic.main.news_fragment.*
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import javax.inject.Inject

class NewsFragment : RxBaseFragment() {

companion object {
private val KEY_REDDIT_NEWS = "redditNews"
}

@Inject lateinit var newsManager: NewsManager
private var redditNews: RedditNews? = null
private val newsManager by lazy { NewsManager() }

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
KedditApp.newsComponent.inject(this)
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return container?.inflate(R.layout.news_fragment)
Expand Down Expand Up @@ -60,9 +67,9 @@ class NewsFragment : RxBaseFragment() {

private fun requestNews() {
/**
* first time will send empty string for after parameter.
* first time will send empty string for 'after' parameter.
* Next time we will have redditNews set with the next page to
* navigate with the after param.
* navigate with the 'after' param.
*/
val subscription = newsManager.getNews(redditNews?.after ?: "")
.subscribeOn(Schedulers.io())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package com.droidcba.kedditbysteps.features.news

import com.droidcba.kedditbysteps.api.NewsAPI
import com.droidcba.kedditbysteps.api.NewsRestAPI
import com.droidcba.kedditbysteps.commons.RedditNews
import com.droidcba.kedditbysteps.commons.RedditNewsItem
import rx.Observable
import javax.inject.Inject
import javax.inject.Singleton

/**
* News Manager allows you to request news from Reddit API.
*
* @author juancho
*/
class NewsManager(private val api: NewsAPI = NewsRestAPI()) {
@Singleton
class NewsManager @Inject constructor(private val api: NewsAPI) {

/**
*
Expand Down

0 comments on commit 296a7bc

Please sign in to comment.