0

This is my first attempt to try implement dagger in my app but I'm stuck at this for a while now. I'm trying to implement Dagger in a baby step here, so please bear with me.

Here's the current code of my app:

class Login : AppCompatActivity(), LifecycleOwner {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    private fun clickLogin() {

        var loginViewModel = LoginViewModel()
        loginViewModel = ViewModelProviders.of(this).get(LoginViewModel::class.java)
        loginViewModel.getLoginObservable(params)!!.observe(this, Observer { myLoginSession ->
            }
        )
    }
}


class LoginViewModel: ViewModel() {

    private var loginObservable: LiveData<MyLoginSession>? = null
    private var dbRepository: DbRepository? = null

    fun getLoginObservable(params: Map<String, String>): LiveData<MyLoginSession>? {
        dbRepository = DbRepository()

        loginObservable = NetworkRepository.getInstance().login(userType, email, password)
        return loginObservable
    }
}

public class NetworkRepository {

    private WebService webService;
    private static NetworkRepository networkRepository;

    private NetworkRepository(){
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(WebService.SERVER_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        webService = retrofit.create(WebService.class);
    }

    public synchronized static NetworkRepository getInstance(){
        if (networkRepository == null){
            networkRepository = new NetworkRepository();
        }
        return networkRepository;
    }

    public LiveData<MyLoginSession> login(int userType, String email, String password){

        final MutableLiveData<MyLoginSession> data = new MutableLiveData<>();

        HashMap<String, Object> params = new HashMap<>();
        params.put("userType",userType);
        params.put("email",email);
        params.put("password",password);

        webService.login(params).enqueue(new Callback<MyLoginSession>() {
            @Override
            public void onResponse(Call<MyLoginSession> call, Response<MyLoginSession> response) {
                Log.v(TAG,"Response code: " + response.code());
                }

            @Override
            public void onFailure(Call<MyLoginSession> call, Throwable t) {
                data.setValue(null);
            }
        });

        return data;
    }
}

Now I'm trying to implement DI using Dagger for the function login under NetworkRepository first.

So I added these dependencies below first:

ext {
    daggerVer = "2.22.1"
}

implementation "com.google.dagger:dagger:$daggerVer"
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVer"
compileOnly 'javax.annotation:javax.annotation-api:1.3.2'

And created AppModule class as below:

@Module
public class AppModule {

    @Provides
    WebService providesWebService(){
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

        return new Retrofit.Builder()
                .baseUrl(WebService.SERVER_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(WebService.class);
    }
}

And changed my NetworkRepository class to below:

@Singleton
public class NetworkRepository {
    private WebService webService;

    @Inject
    private NetworkRepository(WebService webService){
        this.webService = webService;
    }

    public LiveData<MyLoginSession> login(int userType, String email, String password){

            final MutableLiveData<MyLoginSession> data = new MutableLiveData<>();

            HashMap<String, Object> params = new HashMap<>();
            params.put("userType",userType);
            params.put("email",email);
            params.put("password",password);

            webService.login(params).enqueue(new Callback<MyLoginSession>() {
                @Override
                public void onResponse(Call<MyLoginSession> call, Response<MyLoginSession> response) {
                    Log.v(TAG,"Response code: " + response.code());
                    }

                @Override
                public void onFailure(Call<MyLoginSession> call, Throwable t) {
                    data.setValue(null);
                }
            });

            return data;
        }
}

And my LoginViewModel to

@Singleton
class LoginViewModel: ViewModel() {

    @Inject lateinit var networkRepository: NetworkRepository

    @Inject
    fun getLoginObservable(params: Map<String,String>):LiveData<MyLoginSession>{
        DaggerAppComponent.builder().build.buildWebService(this)
        loginObservable = networkRepository.login(userType, email, password)
        return loginObservable
    }
}

If my code on trying to use Dagger above is confusing, it's most probably (obviously) because of the confusion that I faced while trying to implement Dagger in my app.. I went through tons of tutorial and while I faced little problem implementing Dagger in those tutorials' projects, it all went haywire when I tried to implement Dagger in my own app.

I can't compile the code above because it returns Unresolved reference: DaggerAppComponent ; this issue should be fixed after building the app but it doesn't, so I'm pretty sure there's other issue with my Dagger code.

I tried to backtrack and re-do the Dagger implementation several times but now I'm moving in a circle and I literally feels like putting a Dagger in my heart.

imin
  • 4,504
  • 13
  • 56
  • 103
  • Dagger can be a ball-ache to get your head around due to the many different ways it can be used - a lot of examples will include non-basic approaches that just exacerbate its complexity. Take a look at these two articles that simplify it (the first is especially helpful) https://medium.com/@elye.project/dagger-2-for-dummies-in-kotlin-with-one-page-simple-code-project-618a5f9f2fe8 https://medium.com/@Zhuinden/that-missing-guide-how-to-use-dagger2-ef116fbea97 – Ivan Wooll Apr 27 '19 at 16:48
  • I've actually read the article you gave but in some way it makes me even more confused. In all other articles, `@Inject` is used to request dependencies, but this 2 articles used `@Inject` to create object that we want to inject to others too... 8-@ – imin Apr 27 '19 at 17:05
  • All that is trying to say is that you can mark constructors of classes that you own with the `@Inject` annotation so that you can inject these without the need for a module. It's simply a shortcut for your own classes – Ivan Wooll Apr 27 '19 at 17:10

1 Answers1

0

I had this problem in the past. I fixed it using this code:

apply plugin: 'kotlin-kapt'

dependencies {
    def daggerVer = 2.22.1 // or latest version

    implementation "com.google.dagger:dagger:$daggerVer"
    implementation "com.google.dagger:dagger-android-support:$daggerVer"
    kapt "com.google.dagger:dagger-android-processor:$daggerVer"
    kapt "com.google.dagger:dagger-compiler:$daggerVer"
}

see DaggerAppComponent not created

kingston
  • 11,053
  • 14
  • 62
  • 116